tobz.nz's avatar

Mocking in feature test

Hi,

I'm having an issue with mocking in a feature test - maybe this is bad practice(is mocking more a unit test thing?)

Anyway, the mock seems to be setup in the test context, but then the concrete class is returned from ioc in the app when the route is called.


function testExample() {
    $this->mock(MyClass::class, function ($mock) {
        $mock->shouldReceive('someMethod')->once()->andReturn(new ResponseClass);
    });

    dump($this->app->make(MyClass::class)); // dumps mock from IOC

    $this->actingAs($user)->post(route('resource.store'))->assertSuccessful(); // retrieves concrete MyClass from IOC

}

Can anyone point me to what I'm doing wrong here?

0 likes
9 replies
Talinon's avatar

@tobz.nz

How are you resolving MyClass from within your app code? If you are directly instantiating it with new then mocking will have no impact. You need to resolve it out of the container from within your app.

If you need further assistance, post your resource.store endpoint code and I'll try to help.

tobz.nz's avatar

I'm instantiating it the same way as the example $this->app->make(MyClass::class). Well actually It had a constructor argument so it was $this->app->make(MyClass::class, ['arg' => $arg]) - this seems to have been the main issue. The IOC seems to treat it as a new thing if there is an argument.

I've now changed it to use a make() method on my class, so it becomes $this->app->make(MyClass::class)->make($arg) - this is now loading my mock in the app ccode.

Now my problem is, although the mock is retrieved from the container, the method I'm testing for is not called. Not that it is actually a Partial Mock so the concrete class is still used, but one particular method is supposed to be overloaded by the mock. This is not happening for some reason I've not yet figured out.

Talinon's avatar

@tobz.nz

It is expected behaviour to return a new instance when parameters are provided.

Check this reference for more details:

https://github.com/laravel/framework/issues/25041

To get around that, you should be able to make this work with rewriting your test:


$mock = \Mockery::mock(MyClass::class)->makePartial();

$mock->shouldReceive('someMethod')->once()->andReturn(new ResponseClass);

app()->bind(MyClass::class, function() use ($mock) {

    return $mock;

});

tobz.nz's avatar

I get Illegal offset type in isset or empty with that method.

... where I'm getting Serialization of 'Closure' is not allowed with the previous method. Haha, can't win at this.

Talinon's avatar

Where do you get that error? in the test or the app code?

Could you paste the stack?

tobz.nz's avatar

this is when running the test. App all works as expected.

Stack:

[2019-11-13 10:08:45] testing.ERROR: Serialization of 'Closure' is not allowed {"userId":3,"exception":"[object] (Exception(code: 0): Serialization of 'Closure' is not allowed at /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Queue/Queue.php:139)
[stacktrace]
#0 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Queue/Queue.php(139): serialize(Object(Mockery_2_App_Jobs_ProcessJob))
#1 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Queue/Queue.php(110): Illuminate\Queue\Queue->createObjectPayload(Object(Mockery_2_App_Jobs_ProcessJob), NULL)
#2 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Queue/Queue.php(88): Illuminate\Queue\Queue->createPayloadArray(Object(Mockery_2_App_Jobs_ProcessJob), NULL, '')
#3 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Queue/SyncQueue.php(37): Illuminate\Queue\Queue->createPayload(Object(Mockery_2_App_Jobs_ProcessJob), NULL, '')
#4 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(184): Illuminate\Queue\SyncQueue->push(Object(Mockery_2_App_Jobs_ProcessJob))
#5 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(160): Illuminate\Bus\Dispatcher->pushCommandToQueue(Object(Illuminate\Queue\SyncQueue), Object(Mockery_2_App_Jobs_ProcessJob))
#6 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(73): Illuminate\Bus\Dispatcher->dispatchToQueue(Object(Mockery_2_App_Jobs_ProcessJob))
#7 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Bus/PendingDispatch.php(112): Illuminate\Bus\Dispatcher->dispatch(Object(Mockery_2_App_Jobs_ProcessJob))
#8 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php(399): Illuminate\Foundation\Bus\PendingDispatch->__destruct()
#9 /Users/tobyevans/Code/alttune/app.alttune/app/Http/Controllers/UploadController.php(217): dispatch(Object(Mockery_2_App_Jobs_ProcessJob))
#10 [internal function]: App\Http\Controllers\UploadController->store(Object(App\Http\Requests\CreateUploadRequest))
#11 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): call_user_func_array(Array, Array)
#12 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\Routing\Controller->callAction('store', Array)
#13 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Routing/Route.php(219): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), Object(App\Http\Controllers\UploadController), 'store')
#14 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Routing/Route.php(176): Illuminate\Routing\Route->runController()
#15 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Routing/Router.php(680): Illuminate\Routing\Route->run()
#16 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\Routing\Router->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#17 /Users/tobyevans/Code/alttune/app.alttune/app/Http/Middleware/EnsureUserConfirmed.php(31): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#18 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): App\Http\Middleware\EnsureUserConfirmed->handle(Object(Illuminate\Http\Request), Object(Closure))
#19 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(41): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#20 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Routing\Middleware\SubstituteBindings->handle(Object(Illuminate\Http\Request), Object(Closure))
#21 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(43): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#22 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Auth\Middleware\Authenticate->handle(Object(Illuminate\Http\Request), Object(Closure))
#23 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(76): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#24 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Foundation\Http\Middleware\VerifyCsrfToken->handle(Object(Illuminate\Http\Request), Object(Closure))
#25 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#26 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#27 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(56): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#28 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#29 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#30 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure))
#31 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(66): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#32 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Cookie\Middleware\EncryptCookies->handle(Object(Illuminate\Http\Request), Object(Closure))
#33 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#34 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Routing/Router.php(682): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#35 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Routing/Router.php(657): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request))
#36 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Routing/Router.php(623): Illuminate\Routing\Router->runRoute(Object(Illuminate\Http\Request), Object(Illuminate\Routing\Route))
#37 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Routing/Router.php(612): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#38 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(176): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#39 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}(Object(Illuminate\Http\Request))
#40 /Users/tobyevans/Code/alttune/app.alttune/vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#41 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Fideloper\Proxy\TrustProxies->handle(Object(Illuminate\Http\Request), Object(Closure))
#42 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#43 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle(Object(Illuminate\Http\Request), Object(Closure))
#44 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#45 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle(Object(Illuminate\Http\Request), Object(Closure))
#46 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#47 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle(Object(Illuminate\Http\Request), Object(Closure))
#48 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(62): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#49 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle(Object(Illuminate\Http\Request), Object(Closure))
#50 /Users/tobyevans/Code/alttune/app.alttune/vendor/itsgoingd/clockwork/Clockwork/Support/Laravel/ClockworkMiddleware.php(27): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#51 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Clockwork\Support\Laravel\ClockworkMiddleware->handle(Object(Illuminate\Http\Request), Object(Closure))
#52 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#53 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(151): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#54 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(116): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))
#55 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php(434): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))
#56 /Users/tobyevans/Code/alttune/app.alttune/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php(252): Illuminate\Foundation\Testing\TestCase->call('POST', 'https://app.alt...', Array, Array, Array, Array)
#57 /Users/tobyevans/Code/alttune/app.alttune/tests/Feature/UploadTest.php(91): Illuminate\Foundation\Testing\TestCase->post('https://app.alt...', Array)
#58 /Users/tobyevans/Code/alttune/app.alttune/tests/Feature/UploadTest.php(188): Tests\Feature\UploadTest->createValidSlaveFIle(Object(App\User))
#59 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/src/Framework/TestCase.php(1400): Tests\Feature\UploadTest->testStoreSlaveFileUpload()
#60 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/src/Framework/TestCase.php(1020): PHPUnit\Framework\TestCase->runTest()
#61 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/src/Framework/TestResult.php(691): PHPUnit\Framework\TestCase->runBare()
#62 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/src/Framework/TestCase.php(752): PHPUnit\Framework\TestResult->run(Object(Tests\Feature\UploadTest))
#63 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/src/Framework/TestSuite.php(569): PHPUnit\Framework\TestCase->run(Object(PHPUnit\Framework\TestResult))
#64 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/src/Framework/TestSuite.php(569): PHPUnit\Framework\TestSuite->run(Object(PHPUnit\Framework\TestResult))
#65 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/src/Framework/TestSuite.php(569): PHPUnit\Framework\TestSuite->run(Object(PHPUnit\Framework\TestResult))
#66 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(616): PHPUnit\Framework\TestSuite->run(Object(PHPUnit\Framework\TestResult))
#67 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/src/TextUI/Command.php(200): PHPUnit\TextUI\TestRunner->doRun(Object(PHPUnit\Framework\TestSuite), Array, true)
#68 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/src/TextUI/Command.php(159): PHPUnit\TextUI\Command->run(Array, true)
#69 /Users/tobyevans/Code/alttune/app.alttune/vendor/phpunit/phpunit/phpunit(61): PHPUnit\TextUI\Command::main()
#70 {main}
"} 
Talinon's avatar

You're using it in a queue.. yeah, that won't work because of the closure.

Try this instead:

app()->offsetSet(MyClass::class, $this->mock(MyClass::class, function ($mock) {
    $mock->shouldReceive('someMethod')->once()->andReturn(new ResponseClass);
}));        

Talinon's avatar

I have to head out.. if that doesn't work I'll check back in a couple hours.

tobz.nz's avatar

Nope doesn't seem to make a difference. Giving up on this for now. Move on to the then thing and come back to it later. Thanks for your help though :)

Please or to participate in this conversation.