TJ is too short
TJ is too short

Reputation: 873

Testing Laravel custom package by mocking dependency

I'm still in the process of learning about Laravel and Dependency Injection. I understand the concept, but I don't know how to mock a dependency in this specific case:

MyController.php

use Illuminate\Routing\Controller;    
use MyPackage\Services\ServiceInterface;

class MyController extends Controller{
    protected $service;

    public function __construct(ServiceInterface $service)
    {
        $this->service = $service;
    }    
}

MyServiceProvider.php

use Illuminate\Support\ServiceProvider;

class MyServiceProvider extends ServiceProvider{

    public function register()
    {
        $this->app->bind('MyPackage\Services\ServiceInterface', function ($app) {
            return new MyPackage\Services\ConcreteService(['key'=>'123'], $app->make('GuzzleHttp\Client'));
        });
    }    
}

So, as you can see, I have a controller that requires an instance of ServiceInterface. That instance is being resolved in the ServiceProvider. The constructor of ConcreteService requires a client to perform Http request to an API. This Http is being resolved by the Service container (It will be an instance of Guzzle).

Now, how can I mock this instance of Guzzle on my tests?

The ideal result is doing something like this:

MyTest.php

...
$this->post(route('routeToActionInMyController'), $params);

So, in my tests I just need to hit the route that will be using an specific method of MyController.php but I don't need a "real" Guzzle instance. I just need to mock the response to test if MyController behaves in the expected way (and stores things in the database properly).

How can I instruct the Service Container to inject a Mocked object during tests only? Or am I doing this in the completely wrong way?

Any help will be appreciated.

Thanks in advance

Upvotes: 0

Views: 2163

Answers (1)

apokryfos
apokryfos

Reputation: 40663

In your test class:

class TestingSomething extends TestCase {
     protected function setUp() {
          parent::setUp();
          $mockServiceInterface = $this->getMockBuilder(ServiceInterface::class)->getMock();
          $this->app->instance(ServiceInterface::class,$mockServiceInterface);
     }

     public function testPostToRoute() {
        $this->post(route('routeToActionInMyController'), $params);
    }
 } 

This should replace what's already bound in the service container with that mock instance.

Refer to the PHPUnit manual on chapter 9. Test doubles for what you can do with the mock builder and resulting mocks.

Upvotes: 3

Related Questions