laravelphpunit

Artisan Output not working in a test when calling Model methods


I am trying to add a new Command to a set of existing Commands around an existing Model.

The other tests for the other Commands around this all work just fine as expected.

However, this new test + Command stops writing to Artisan::output() as soon as I add any method call on the Webhook model. count(), first(), all(). Doesn't matter, and it also doesn't matter if I assign it to a variable or use it in the least. There's no Exception, there's no PHP/Laravel log error. The exact same command works perfectly when called directly from bash artisan. It's the strangest thing I've ever seen.

Test:

<?php

namespace Tests\Unit\Console\Commands\Webhook\Customer;

use App\Models\Shopify\Webhook;
use Illuminate\Support\Facades\Artisan;
use Tests\TestCase;

class ProcessUpdateWebhooksTest extends TestCase
{
    /** @test */
    public function thisWorksRightHere()
    {
        Artisan::call('boxer:process-customer-update-webhooks');

        $this->assertStringContainsString(
            'Hey',
            Artisan::output()
        );
    }
}

Command (commenting Webhook::count() makes it pass, otherwise the output of the command is ''' and it fails.

<?php

namespace App\Console\Commands\Webhook\Customer;

use App\Models\Shopify\Webhook;
use Illuminate\Console\Command;

class ProcessUpdateWebhooks extends Command
{
    protected $signature = 'boxer:process-customer-update-webhooks
        {--w|webhooks=25 : The maximum number of webhooks to process}';

    protected $description = 'Process orders/create webhooks from Shopify (default 25)';

    public function handle()
    {
        Webhook::count();
        $this->info('Hey');
    }
}

phpunit.xml section:

    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="BCRYPT_ROUNDS" value="4"/>
        <env name="CACHE_DRIVER" value="array"/>
        <!-- <env name="DB_DATABASE" value="testing"/> -->
        <env name="MAIL_MAILER" value="array"/>
        <env name="QUEUE_CONNECTION" value="sync"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="TELESCOPE_ENABLED" value="false"/>
    </php>

Test Output:

PHPUnit 9.6.19 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 00:02.211, Memory: 48.50 MB

There was 1 failure:

1) Tests\Unit\Console\Commands\Webhook\Customer\ProcessUpdateWebhooksTest::thisWorksRightHere
Failed asserting that '' contains "Hey".

/Users/peterdemarco/code/projects/boxer/tests/Unit/Console/Commands/Webhook/Customer/ProcessUpdateWebhooksTest.php:16
/Users/peterdemarco/code/projects/boxer/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:61

All other tests (again, including all other tests for this Model and Commands that use this Model) work completely fine.

What am I missing??


Solution

  • That may happen because you are not using $this->artisan to test a command. So other stuff may not be set as it is running in testing mode.

    Switch your test to the right way:

    <?php
    
    namespace Tests\Unit\Console\Commands\Webhook\Customer;
    
    use App\Models\Shopify\Webhook;
    use Illuminate\Support\Facades\Artisan;
    use Tests\TestCase;
    
    class ProcessUpdateWebhooksTest extends TestCase
    {
        /** @test */
        public function thisWorksRightHere()
        {
            $this->artisan('boxer:process-customer-update-webhooks')
                ->expectsOutputToContain('Hey');
        }
    }
    

    It is super important that you chain any assertion to the artisan() call. If you don't do so, the command will run before expected, please chain your assertions strictly talking about the command.