#Capturing artisan command output in tests

15 messages · Page 1 of 1 (latest)

hollow pumice
#

I'm writing some custom artisan commands, and I've hit a snag in testing.
A simplified version of my test looks like this:

public function test_output(): void
{
    $this->assertEquals(0, Artisan::call('app:hello'));
    $output = Artisan::output();
    dump($output);
    $this->assertEquals(1, 
      preg_match('/Hello (\w+)/', $output, $matches));
    $this->assertEquals('World', $matches[1]);
}

This fails, because $output is an empty string.
I think this is somehow related to testing, because the same commands work in tinker:

$ php artisan tinker
Psy Shell v0.12.9 (PHP 8.4.10 — cli) by Justin Hileman
> Artisan::call('app:hello');
= 0

> Artisan::output();
= "Hello World\n"

And to pre-empt this: I know about
$this->artisan('app:hello')->expectsOutputToContain('Hello');

That works, but is not what I want. I need the actual output text from the command, so I can extract some piece of it for use in the later parts of the test.

placid idol
#

Did you try running it with $this->call()? Artisan::call() might change the output buffer, and thus in tests wouldn't be able to capture it

hollow pumice
#

What is the $this in this context? My test class? it has a call function, but that's not calling artisan commands.

#

I've tried using $this->artisan('app:hello')->run() instead of Artisan::call, but same problem.

placid idol
#

I meant that

hollow pumice
#

The first thing run() does is call mockConsoleOutput, which creates a mocked BufferOutput, so I assume that's where all the output goes, and why it doesn't get captured elsewhere.

#

I may have to test this command by calling handle() on it directly, not going through artisan at all. Use a different vise.

jaunty cipher
#

It works fine when I try it.

Artisan::command('app:hello', function () {
    $this->info('Hello World');
});
$this->assertEquals(0, Artisan::call('app:hello'));
$output = Artisan::output();
dump($output);
$this->assertEquals(
    1,
    preg_match('/Hello (\w+)/', $output, $matches)
);
$this->assertEquals('World', $matches[1]);

Result

PHPUnit 11.5.25 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.22
Configuration: /var/www/html/phpunit.xml
"Hello World\n" // tests/Feature/TempTest.php:19
Time: 00:00.351, Memory: 26.00 MB

OK (1 test, 3 assertions)

Process finished with exit code 0
hollow pumice
#

So something in my application must be different, then.

#

Yes. When I do the same in a different Laravel app, it works. Could it be some application middleware screwing things up? Some setting somewhere? Sigh.

jaunty cipher
#

same laravel and phpunit version?

hollow pumice
#

yes

jaunty cipher
#

Does your command use "echo" ? That's the only explanation I can think of. Because that would write directly to stdout in stead of using the OutputInterface.

hollow pumice
#

I couldn't figure out what's wrong with my project, but found a workaround. I'm creating an instance of the Command class, and setting it up with my own BufferesOutput object, which I can fetch the output from after I call handle(). It's a weird hack, but it works intime for my vacation break.