How to inspect the actual Laravel Command output while writing tests?

3.8k Views Asked by At

I was writing a very basic test for a Laravel Artisan Console Command, like this:

$this->artisan("my-command", ["--some-option" => "some-value"])
     ->expectsOutput("the expected output");

The test didn't pass. I got really troubled because "the expected output" was exactly what the command was outputting when executed mannualy.

But that's ok, I just have to inspect what the command output actually is when executed through automated tests, right? But wait, how do I do that?

I tried the following:

$output = new BufferedConsoleOutput();
Artisan::call("my-command", ["--some-option", "some-value"], $output);
// dd($output->fetch()
$this->assertTrue($output->fetch() === "the expected output");

But $output->fetch() seems to be always empty.

In brief: How do I print the actual output of a Laravel command in the context of a test?

1

There are 1 best solutions below

0
On

If you prevent Laravel from mocking the console output, you can capture it for inspection.

Assuming you have this test that fails:

public function testStuffDoesntBreak(): void
{
    $this->artisan("my-command", ["--some-option" => "some-value"])
        ->expectsOutput("the expected output");
}

You can rewrite it to this:

use Illuminate\Support\Facades\Artisan;
...

public function testStuffDoesntBreak(): void
{
    $this->withoutMockingConsoleOutput()
        ->artisan("my-command", ["--some-option" => "some-value"]);
    // capture the text output from the command
    $result = Artisan::output();
    // use standard text assertions
    $this->assertEquals("the expected output", $result);
}

When you've disabled console mocking, the artisan() method stops being fluent and instead returns the exit code of the command. But it does allow the Artisan facade to access its output.


Whether you want to rewrite your tests to always mock the output, or just change them on the fly when trying to debug an error, is down to personal preferences. I've done the latter, as I'd rather not miss out on fluent methods like expectsTable().