Lumen-framework: Unit testing Jobs using mock object always fails

Created on 28 Jul 2015  路  5Comments  路  Source: laravel/lumen-framework

Unit testing in Lumen to determine if a Job was dispatched always fails. Live testing in Lumen shows the job to work as expected. The unit test also works as expected when moved into a full instance of Laravel.

It appears that _app('Illuminate\Contracts\Bus\Dispatcher')_ will return in instance of _Illuminate\Bus\Dispatcher_ even though if you inspect _app()->instances_ you can see _'Illuminate\Contracts\Bus\Dispatcher' => Mockery_0_Illuminate_Bus_Dispatcher_.

Calling _app('Illuminate\Contracts\Bus\Dispatcher')_ in a full Laravel instance will return _Mockery_0_Illuminate_Bus_Dispatcher_ as expected.

Error:
Mockery\Exception\InvalidCountException: Method dispatch(object(Mockery\Matcher\Type)) from Mockery_0_Illuminate_Bus_Dispatcher should be called at least 1 times but called 0 times.

Job Example

namespace App\Jobs;
class ExampleJob extends Job
{
    public function handle()
    {
    }
}

Unit Test Example

class ExampleTest extends TestCase
{
    public function testBasicExample()
    {
        $this->expectsJobs(App\Jobs\ExampleJob::class);
        $job = new \App\Jobs\ExampleJob();
        app('Illuminate\Contracts\Bus\Dispatcher')->dispatch($job);
    }
}

Most helpful comment

I ran into the same bug while using expectJobs() in a test with a fresh Lumen application.

I don't understand why this bug is closed.

$ composer show -i
laravel/lumen-framework           v5.2.7
mockery/mockery                   0.9.5

All 5 comments

The Lumen application's overloaded make() implementation is triggering registerBusBindings() and binding over the the previously mocked instance setup in expectsJobs().

I'm unsure of the whether this is a bug, but removing the available binding for the Dispatcher prevents the mock from being overwritten:

public function testBasicExample()
{
    unset ($this->app->availableBindings['Illuminate\Contracts\Bus\Dispatcher']);       
    $this->expectsJobs(App\Jobs\ExampleJob::class);
    $job = new \App\Jobs\ExampleJob();
    app('Illuminate\Contracts\Bus\Dispatcher')->dispatch($job);
}

You can also trigger the registration prior to setting up the mock by just calling app('Illuminate\Contracts\Bus\Dispatcher') somewhere earlier in the test.

It could also make sense to de-register the available binding or trigger the registration from within ApplicationTrait::expectsJob().

Update Having said that, at the very least it might be worth just updating the documentation to highlight the fact that you need to resolve the bindings prior to setting up mocks.

Thoughts?

Feel free to discuss on the forums.

This is very unexpected behavior. I just battled this for quite some time. Having to unset the IOC binding feels like hacky code to work around a bug.

It seems like this issue was closed without giving it any consideration.

@jessedc Thanks for posting the solution here... it worked for me.

@jessedc Been spinning my wheels on this as well. Thanks for the solution.

Though I agree with @bkuhl this does seem a bit hacky.

I ran into the same bug while using expectJobs() in a test with a fresh Lumen application.

I don't understand why this bug is closed.

$ composer show -i
laravel/lumen-framework           v5.2.7
mockery/mockery                   0.9.5
Was this page helpful?
0 / 5 - 0 ratings