Testing with Service Container
The backbone of Laravel is service container. Service container is used for resolving classes and dependency injection. Container comes as a standalone package, so you don’t have to have Laravel installed to use it. Service container can be very handy when testing. Let’s look at how we can use it .
Our basic set up consists of a route in web.php file:
OrdersController.php
ShopifyConnectorInterface is injected in index() method of the controller and looks like this:
ShopifyConnector class is bound as the interface implementation in AppServiceProvider. ShopifConnector is instantiated using Shopify credentials stored in the configuration file.
Laravel’s service container will look at the interface, figure out that it is bound to ShopifyConnector, and instantiate it for us. ShopifyConnector::getOrders() makes a call to Shopify API and returns back orders. For demonstration purposes we JSON encode them when returning. In real life though, the orders will be passed to a view and the view will be returned from the controller.
The task is to test the code without hitting an actual API. For that purposes we can create ShopifyConnectorFake and make it implement ShopifyConnectorInterface.
Now in our test we can bind ShopifyConnectorFake to the interface.
As a side note: we use $this->withoutExceptionHandling() to avoid getting “Ooops” error display, because it is not very readable in the command line interface.
Most of the times we need to test not only successful result returned from ShopifyConnector, but also an error result. We could create another ShopifyConnectorFake with its method getOrders() returning an error response. And then another one, for a different response… Eventually we will end up with a lot of connector fakes. A different approach would be to create a mock of ShopifyConnector and make its method return what we want.
First we create a mock of the ShopifyConnector class. We need to disable original constructor, because in production code we are passing configuration parameters. We define methods that we want to mock. In our case it is one: getOrders(). There can be more though. Also note only the methods you define will be mocked. Other methods will behave as normal. Then we tell phpunit we expect method getOrders() to be called once and return error response to us. Now we can bind the mocked connector to ShopifyConnectorInterface as an instance. In this case when container will be asked to resolve the interface, it will give us back the bound instance.
From the examples above we can see service container that comes with Laravel makes the application more testable and easier to test.
Resources: