Jul 15, 2013
Table of contents:
In last week’s post I looked at using Repositories in Laravel 4 to abstract the database layer away from the Controller. This enables you to easily switch out the type of database or the specific ORM that you want to use without having to change any of your Controller code in your actual application.
This week I want to look at how you should structure your Controllers to make them testable. Testing your Controllers is a critical aspect of building a solid web application, but it is important that you only tests the appropriate bits of your application.
Fortunately, Laravel 4 makes separating the concerns of your Controller really easy. This makes testing your Controllers really straight forward as long as you have structured them correctly.
So let’s get started!
Before I get into how to structure your Controllers for testability, first its important to understand what exactly we need to test for.
As I mentioned in Setting up your first Laravel 4 Controller, Controllers should only be concerned with moving data between the Model and the View. You don’t need to verify that the database is pulling the correct data, only that the Controller is calling the right method. Therefore your Controller tests should never touch the database.
This is really what I’m going to be showing you today because by default it is pretty easy to slip into coupling the Controller and the Model together.
As a way of illustrating what I’m trying to avoid, here is an example of a Controller method:
public function index()
This is a bad practice because we have no way of mocking
User::all(); and so the associated test will be forced to hit the database.
In order to get around this problem, we have to inject the dependency into the Controller. Dependency Injection is where you pass the class an instance of an object, rather than letting that object create the instance for its self.
By injecting the dependency into the Controller, we can pass the class a mock instead of the database instead of the actual database object itself during our tests. This means we can test the functionality of the Controller without ever touching the database.
As a general guide, anywhere you see a class that is creating an instance of another object it is usually a sign that this could be handled better with dependency injection. You never want your objects to be tightly coupled and so by not allowing a class to instantiate another class you can prevent this from happening.
Laravel 4 has a beautiful way of handling Dependency Injection. This means you can resolve classes without any configuration at all in many scenarios.
This means that if you pass a class an instance of another class through the constructor, Laravel will automatically inject that dependency for you!
Basically, everything will work without any configuration on your part.
So now you understand the problem and the theory of the solution, we can now fix the Controller so it isn’t coupled to the database.
If you remember back to last week’s post on Laravel Repositories, you might have noticed that I already fixed this problem.
So instead of doing:
public function index()
public function __construct(User $user)
$this->user = $user;
* Display a listing of the resource.
* @return Response
public function index()
UserController class is created, the
__construct method is automatically run. The
__construct method is injected with an instance of the
User repository, which is then set on the
$this->user property of the class.
Now whenever you want to use the database in your methods, you can use the
The real magic happens when you come to write your Controller tests. Now that you are passing an instance of the database to the Controller, you can mock the database instead of actually hitting the database. This will not only improve performance, but you won’t have any test data lying around after your tests.
First thing I’m going to do is to create a new folder under the
tests directory called
functional. I like to think of Controller tests as being functional tests because we are testing the incoming traffic and the rendered view.
Next I’m going to create a file called
UserControllerTest.php and write the following boilerplate code:
class UserControllerTest extends TestCase
If you remember back to my post, What is Test Driven Development?, I talked about Mocks as being, a replacement for dependent objects.
Mockery allows you to mock objects in your project so you don’t have to use the real dependency. By mocking an object, you can tell Mockery which method you would like to call and what you would like to be returned.
This enables you to isolate your dependencies so you only make the required Controller calls in order for the test to pass.
For example, if you wanted to call the
all() method on your database object, instead of actually hitting the database you can mock the call by telling Mockery you want to call the
all() method and it should return an expected value. You aren’t testing whether the database can return records or not, you only care about being able to trigger the method and deal with the return value.
Installing Mockery Like all good PHP packages, Mockery can be installed through Composer.
To install Mockery through Composer, add the following line to your
Next, install the package:
composer install -dev
Now to set up Mockery, we have to create a couple of set up methods in the test file:
public function setUp()
$this->mock = $this->mock('Cribbb\Storage\User\UserRepository');
public function mock($class)
$mock = Mockery::mock($class);
setUp() method is run before any of the tests. Here we are grabbing a copy of the
UserRepository and creating a new mock.
$this->app->instance tells Laravel’s IoC container to bind the
$mock instance to the
UserRepository class. This means that whenever Laravel wants to use this class, it will use the mock instead.
Next you can write your first Controller test:
public function testIndex()
In this test I’m asking the mock to call the
all() method once on the
UserRepository. I then call the page using a GET request and then I assert that the response was ok.
Testing Controllers shouldn’t be as difficult or as complicated as it is made out to be. As long as you isolate the dependencies and only test the right bits, testing Controllers should be really straight forward.
In next week’s tutorial, I’m going to take a much deeper look at using Mockery in your tests. Mockery is an essential package for writing good applications and it is so powerful it deserves a post dedicated to it.