I am trying to mock a class to prevent it from having to call 3rd party apis. But when setting up the mock, it doesn't seem to affect the controller action. I did try replacing the $this->postJson()
by manually creating instances of the Request
- and OEmbedController
-classes. The create()
-method is getting called, but I am receiving an error from Mockery that it isn't.
What am I doing wrong here?
Error:
Mockery\Exception\InvalidCountException : Method create() from Mockery_2_Embed_Embed should be called exactly 1 times but called 0 times.
Test:
class OEmbedTest extends TestCase
{
public function tearDown()
{
Mockery::close();
}
/**
* It can return an OEmbed object
* @test
*/
public function it_can_return_an_o_embed_object()
{
$url = 'https://www.youtube.com/watch?v=9hUIxyE2Ns8';
Mockery::mock(Embed::class)
->shouldReceive('create')
->with($url)
->once();
$response = $this->postJson(route('oembed', ['url' => $url]));
$response->assertSuccessful();
}
}
Controller:
public function __invoke(Request $request)
{
$info = Embed::create($request->url);
$providers = $info->getProviders();
$oembed = $providers['oembed'];
return response()
->json($oembed
->getBag()
->getAll());
}
__invoke
method tohandle
it'll look nicer. You are creating an instance of Embed within the (invoke) method; thats untestable without the mock. I personally avoid mocking anything and resort to stubs / fake classes etc. I do recommend letting the Laravel build / create / instantiate the Embed object before it hits the controller. Which means creating a service provider which will take care of the instantiating the Embed object for you and perhaps placing it in the$request
itself. Do add more info about route you are accessing. – Kyslik$this->app->bind()
. Sure that is possible, but shouldn't it be possible without that? Because then I need an Interface, etc, which feels cumbersome for this little test. – Fredrik->bind(Embed\Embed::class, function($app){ return Embed\Embed::create($app['request']->url); });
Now I do not know whats going on aftercreate
is called. But in the controller you can now use$info = resolve(Embed\Embed::class)
; obviously you need to do checking if request has url parameter etc (do this within the bind closure). Now in the testsetUp
you need to rebind it, for more information read stackoverflow.com/questions/50262576/… – Kyslik