This is related to this question, but following that solution did not fix my issue. I also realize that Laravel's own documentation states that you should not mock the Request object, but I'm not sure how else to go about writing this test.
Here's a semblance of the code I want to test:
public function getThirdSegment()
{
return Request::segment(3);
}
Here's a test I currently have:
/**
* #test
*/
public function indexReturnsOk()
{
$this->prepareForTests();
$this->call('GET', '/api/v1/courses');
$this->assertResponseOk();
$this->assertResponseStatus(200);
}
This is failing because Request::segment(3) is returning null when running PHPUnit. I first tried to mock the Request object like this:
Request::shouldReceive('segment')->andReturn('courses');
But it still returns null. Then I tried this:
$request = m::mock('Illuminate\Http\Request');
$request->shouldReceive('segment')->andReturn('courses');
Input::swap($request);
And the segment method is still returning null. Is there any way to mock the return value of this method?
Update
This code is within a service provider's register method, but I don't think that's the cause of the issue. Hitting the site from a browser does what I would expect it to do, yet running PHPUnit doesn't seem to flesh out either the route or the URL, or anything having to do with the request itself.
Best answer here so far is I was doing it wrong. Service Providers run way before a controller is even loaded, and, when unit testing, Laravel's Illuminate\Foundation\Testing\TestCase loads the application (calling all service providers' both boot and register methods) during execution of the setUp method, way before any calls can be made out during the execution of any individual test.
I tried finding a solution by moving the logic down and got something to work, something along the lines of:
class MyTestClass extends TestCase
{
public function setUp()
{
// No call to parent::setUp()
// From: Illuminate\Foundation\Testing\TestCase
$this->app = $this->createApplication();
$this->client = $this->createClient();
// Not this one!
//$this->app->setRequestForConsoleEnvironment();
$this->app->boot();
// ...
}
public function testWhatever()
{
// Calls to this will now actually have a request object
$this->call('GET', '/api/v1/courses');
}
}
But that just can't be right, at least it doesn't feel so.
Instead, I figure it's probably best not to rely on anything in the Request object from within Service Providers. Instead, why not just inject an object that can do what I need it to do in the controller I want it to? No Service Provider necessary, and I can easily mock any object other than Request in Unit Tests. I should've believed the docs.
Update
Taking this answer to my own question a bit further, I believe my original mistake was that I was utilizing the Request object within a Service Provider. I think, on retrospection, that you should probably never use the Request object at all within a service provider, because providers get loaded for everything related to laravel (including artisan commands, which of course should have no request). My original code worked in the browser, but I probably would have noticed issues had I tried to run any artisan commands.
I came across this looking for a good way to handle a view composer that uses the request, and ultimately ended up going with constructor injection - because Laravel uses the Symfony Request class, it was really easy to "mock" a request with Request::create('http://myurl.com'), and pass it into an instance of my class for testing. Much better than trying to mess with stubbing methods on the request class, and doesn't rely on building up the whole Laravel application.
For clarity's sake, the view composer looks generally like this:
class SiteLayoutComposer extends BaseComposer {
function __construct(Request $request) {
$this->request = $request;
}
public function compose($view)
{
$templateName = preg_match('/siteurlexample/', $this->request->getHost()) ? 'site1' : 'site2';
$view->with('siteLayout', "layouts.sites.{$templateName}");
}
}
And the test:
class SiteLayoutComposerTest extends TestCase {
public function testWillSetTheSiteLayoutToSite1()
{
$request = Request::create('http://www.siteurlexample.com');
$view = View::make('home');
$composer = new SiteLayoutComposer($request);
$composer->compose($view);
$this->assertEquals('layouts.sites.site1', $view->siteLayout);
}
}
Related
In my laravel project I have following interface, repository and controller.
This is Interface
interface TrainingClassTypeInterfaces
{
public function updateTrainingClassType($id, $request);
}
This is Repository
use App\Models\Trainings\AppTrainingClassType;
class TrainingClassTypeEloquent implements TrainingClassTypeInterfaces
{
protected $model;
public function __construct(AppTrainingClassType $appTrainingClassType)
{
$this->model = $appTrainingClassType;
}
public function updateTrainingClassType($id, $request)
{
$response = false;
$isUpdated = $this->model::where('training_class_id',$id)->update([
'app_id' => $request->app_id
]);
....
}
}
This is controller
class TrainingClassTypesController extends \TCG\Voyager\Http\Controllers\VoyagerBaseController
{
protected $trainingService;
public function __construct(TrainingClassTypeEloquent $trainingClassTypeInterfaces) {
$this->trainingService = $trainingClassTypeInterfaces;
}
public function insertOrUpdate()
{
...
$this->trainingService->updateTrainingClassType($id, $request);
..
}
}
Everything working fine till here
As you can see I am using TrainingClassTypeEloquent's method inside TrainingClassTypesController. But it was returning error something like
Argument 1 passed to ...::__construct() must be an instance of
Basically it was asking me to put instance of Model into TrainingClassTypeEloquent class. Then I did as following
$TCTypes = new AppTrainingClassType();
$TCT = new TrainingClassTypeEloquent($TCTypes);
$TCT->updateTrainingClassType($id, $request);
which was working fine but I was confused that this approach is not proper, there should be some proper way.
After googling I found another solution which is singleton binding, and then I tried following in AppServiceProvider
$this->app->singleton(
\App\Services\Voyager\Eloquent\TrainingClassType\TrainingClassTypeInterfaces::class,
\App\Services\Voyager\Eloquent\TrainingClassType\TrainingClassTypeEloquent::class
);
After adding this singleton binding, I notice script was working without providing model instance into TrainingClassTypeEloquent class.
I would like to know how $this->app->singleton() is working, so in this way my concept would be clear about it. If someone knows then kindly guide me about it.
Thank you so much
It is all about BINDING a service to the service container.
What does $this->app->singleton(); method do?
The singleton method binds a class or interface into the service container so that Laravel can maintain dependency (when using an interface as the constructor parameter).
(Actually Singleton is a design pattern. Singleton implementation always returns the same object on subsequent calls instead of a new instance). So $this->app->singleton(); method returns the same object again and again.
Point to be noted that Laravel doc says:
There is no need to bind classes into the container if they do not
depend on any interfaces. The container does not need to be instructed
on how to build these objects, since it can automatically resolve
these objects using reflection.
But your controller class depends on an interface, so the container needs to be informed and to do this, you need to use this $this->app->singleton(); method but there are other ways around.
Again, at the same time, this TrainingClassTypeEloquent::class has a dependency of AppTrainingClassType::class. But in this case, we do not need to worry about that because Laravel uses Reflection API to maintain its dependency as this class does not use interface as like TrainingClassTypesController::class class.
Once you are done with binding the service to the container, Laravel will then automagically put the service onto the constructor method as an argument where the interface is used.
I hope this would help you. You may find more help from this answer.
You need to register TrainingClassTypeEloquent
$this->app->singleton(TrainingClassTypeInterfaces::class, static function ($app) {
return new TrainingClassTypeEloquent(new AppTrainingClassType());
});
Then you can inject it in your Controller
public function insertOrUpdate(TrainingClassTypeInterfaces $trainingService, $id)
{
$trainingService->updateTrainingClassType($id, request());
}
I've been successfully using Mockery with PHPUnit tests lately. Yet, there is a dependency in a project I'm currently working that uses static method calls to interact with an API. I'm struggling to test one particular use case and it feels like I'll find other like this during the development roadmap.
Using this class as an example:
namespace Name\Space;
class User
{
/**
* #return \Name\Space\User[]
*/
public static function list(): array
{
// ...
}
public static function create(array $attrs): User
{
// ...
}
}
In case I just want to assert a method returns a primitive type, such as an array:
Mockery::mock('alias:\Name\Space\User')
->shouldReceive('list')
->andReturn([]);
It works fine, primarily because I'm not testing the array contents.
However, I have to call the create method, which returns an instance of the class itself (User). If I do something like this:
$user = new \Name\Space\User();
Mockery::mock('alias:\Name\Space\User')
->shouldReceive('create')
->andReturn($user);
The alias, obviously, won't work because the class was already loaded through the autoloader (composer's, in this case).
Does anyone have a suggestion on how to workaround this?
What about creating User in a closure?
<?php
$user = Mockery::mock('overload:\Name\Space\User')
->shouldReceive('create')
->andReturnUsing(function() {
return new \Name\Space\User();
});
Mocking static stuff is always painful.
I would recommend creating a Proxy object that is calling the static API calls and just returns the API results and inject this object everywhere you need to call the API.
This way it is easy to test by simply mocking the proxy object.
The proxy object itself can then be tested in an end to end test outside of the pure unit test scope.
You can still do more invasive stuff like this
https://www.pagemachine.de/blog/mocking-static-method-calls/?cn-reloaded=1
But writing code that doesn't belong to your unit tests purely to make something testable doesn't feel right to me.
I'm new to testing and writing testable code, and am looking for some clarification on the correct way to handle this simple scenario. I've read other questions and answers on SO with similar titles but they do not seem to offer a clear answer to what I'm asking.
I have a controller that calls the shipped() method on an instance of my Picking class:
class MyController extends \BaseController {
public function controllerMethod() {
$picking = new Picking;
$picking->shipped($shipmentData);
}
}
The Picking model looks like this:
class Picking extends \Eloquent {
public function order() {
return $this->belongsTo('Order');
}
public function shipped($shipmentData) {
$this->carrier = $shipmentData['Carrier'];
$this->service = $shipmentData['Service'];
$this->is_shipped = true;
$this->save();
$this->order->pickingShipped();
}
}
As you can see, this shipped() method saves some data, and then calls the pickingShipped() method, on it's related Order.
Now, I am trying to write a test for the shipped() method, and I'm not sure the appropriate way to do this. I've read about mocking, but I am confused if this is a situation where mocking is necessary. I've thought of a few possible solutions, but I'm not sure if any of them are correct.
1) Rearrange the code so that the controller calls the pickingShipped() method allowing it to be removed from the shipped() method, simplifying the test.
For example, the last line of the shipped() method would be removed, and the controller code would change to:
$picking = new Picking;
$picking->shipped($shipmentData);
$picking->order->pickingShipped();
2) In the test, use a mock method on order so that the test can simply confirm that the pickingShipped() method gets called.
Something along the lines of what's explained here. That would mean the test could do something like this:
$order->expects($this->once())->method('pickingShipped')
However, I think that would mean that I also need to inject the order dependency rather than relying on the order relationship within the shipped() method, like this:
class Picking extends \Eloquent {
public function order() {
return $this->belongsTo('Order');
}
public function shipped(Order $order, $shipmentData) {
$this->carrier = $shipmentData['Carrier'];
$this->service = $shipmentData['Service'];
$this->is_shipped = true;
$this->save();
$order->pickingShipped();
}
}
And then the code in the controller would have to look like this:
$picking = new Picking;
$picking->shipped($picking->order, $shipmentData);
This feels a little strange, but I'm really not sure what's right.
My question is, what is the proper way to write and test this code? It's easy to test the the shipped() method sets the appropriate data on itself, but what about that call to pickingShipped() at the end? This seems to make the testing more complicated. So should the code be rearranged? If so, how? Or, is this a common use-case for mocking like I outlined in the 2nd option? If so, is it correct to inject the dependency as I'm showing?
I'm not a PHP dev so this might come down to language features being a blocker.
I would suggest that the dependency injection method is better because it calls out the dependency and would allow you to separate your persistence and behavior later. For instance the Picking or Picker might be a better behavior name whilst PickingRecord might be nice for the data.
In any case if you can set default arguments in PHP then I like the last method you used (injection) and you could currently simplify to something like
public function shipped($shipmentData, Order $order = $this->order) {
$this->carrier = $shipmentData['Carrier'];
$this->service = $shipmentData['Service'];
$this->is_shipped = true;
$this->save();
$order->pickingShipped();
}
This then would allow you to ignore the order dependency in production code and inject a double or other type of object as an order in tests and simply assert that the method was called on the order object. Integration tests should continue to monitor that the interfaces still mesh together even though you're injecting doubles in your unit tests.
This would be how I'd attempt to do this in Ruby.
I came up with a solution that I feel good about. It seems pretty obvious now that I see it. All I did was set the $picking->order property to return the mocked order for the test.
$order = Mockery::mock(Order::class);
$picking = new Picking;
$picking->order = $order;
$order->shouldReceive('pickingShipped')
->with($picking)
->once();
$picking->shipped($shipmentData);
Now when the shipped() method calls $this->order, it gets the mocked $order object I defined, and the test works correctly.
This feels like the right solution.
We have Laravel 5 controllers method:
public function getInput()
{
$input = \Request::all();
$links = $input['links'];
$this->startLinks = explode("\n", $links);
return $this;
}
How can we test this single method? How to pass POST request with data to this method? And how to create instance of this controller class in my test method?
This looks like a method which probably shouldn't belong in a controller. If you are serious about testing, I'd highly recommend reading up on the repository pattern. When testing, it will make your life a lot easier to have everything abstracted out of the controllers.=
With that said though, this is still very testable. The main idea is to figure out what needs to be tested and ONLY test that. This means we don't care what the dependencies are doing, only that they are doing and returning something which the rest of the method will need. In this case, it's the Request facade.
Then you want to make sure the variables are set appropriately and that the method returned an instance of that class. It actually ends up being pretty straight forward.
Should look something like this...
public function testGetInput()
{
$requestParams = [
'links' => "somelink.com\nsomeotherlink.com\nandanotherlink.com\ndoesntmatter.com"
];
// Here we are saying the \Request facade should expect the all method to be called and that all method should
// return some pre-defined things which we will use in our asserts.
\Request::shouldReceive('all')->once()->andReturn($requestParams);
// Here we are just using Laravel's IoC container to instantiate your controller. Change YourController to whatever
// your controller is named
$class = App::make('YourController');
// Getting results of function so we can test that it has some properties which were supposed to have been set.
$return = $class->getInput();
// Again change this to the actual name of your controller.
$this->assertInstanceOf('YourController', $return);
// Now test all the things.
$this->assertTrue(isset($return->startLinks));
$this->assertTrue(is_array($return->startLinks));
$this->assertTrue(in_array('somelink.com', $return->startLInks));
$this->assertTrue(in_array('nsomeotherlink.com', $return->startLInks));
$this->assertTrue(in_array('nandanotherlink.com', $return->startLInks));
$this->assertTrue(in_array('ndoesntmatter.com', $return->startLInks));
}
I think you are looking for this.
If your test class extends TestCase you will get a lot of helper methods which will do heavy lifting for you.
function testSomething() {
// POST request to your controller#action
$response = $this->action('POST', 'YourController#yourAction', ['links' => 'link1 \n link2']);
// you can check if response was ok
$this->assertTrue($response->isOk(), "Custom message if something went wrong");
// or if view received variable
$this->assertViewHas('links', ['link1', 'link2']);
}
Codeception extends this functionality even further.
How can I resolve dependencies to a controller that is testable?
How it works: A URI is routed to a Controller, a Controller may have dependencies to perform a certain task.
<?php
require 'vendor/autoload.php';
/*
* Registry
* Singleton
* Tight coupling
* Testable?
*/
$request = new Example\Http\Request();
Example\Dependency\Registry::getInstance()->set('request', $request);
$controller = new Example\Controller\RegistryController();
$controller->indexAction();
/*
* Service Locator
*
* Testable? Hard!
*
*/
$request = new Example\Http\Request();
$serviceLocator = new Example\Dependency\ServiceLocator();
$serviceLocator->set('request', $request);
$controller = new Example\Controller\ServiceLocatorController($serviceLocator);
$controller->indexAction();
/*
* Poor Man
*
* Testable? Yes!
* Pain in the ass to create with many dependencies, and how do we know specifically what dependencies a controller needs
* during creation?
* A solution is the Factory, but you would still need to manually add every dependencies a specific controller needs
* etc.
*
*/
$request = new Example\Http\Request();
$controller = new Example\Controller\PoorManController($request);
$controller->indexAction();
This is my interpretation of the design pattern examples
Registry:
Singleton
Tight coupling
Testable? No
Service Locator
Testable? Hard/No (?)
Poor Man Di
Testable
Hard to maintain with many dependencies
Registry
<?php
namespace Example\Dependency;
class Registry
{
protected $items;
public static function getInstance()
{
static $instance = null;
if (null === $instance) {
$instance = new static();
}
return $instance;
}
public function set($name, $item)
{
$this->items[$name] = $item;
}
public function get($name)
{
return $this->items[$name];
}
}
Service Locator
<?php
namespace Example\Dependency;
class ServiceLocator
{
protected $items;
public function set($name, $item)
{
$this->items[$name] = $item;
}
public function get($name)
{
return $this->items[$name];
}
}
How can I resolve dependencies to a controller that is testable?
What would be the dependencies that you are talking about in a controller?
The to major solution would be:
injecting a factory of services in the controller through constructor
using a DI container to pass in the specific services directly
I am going to try to describe both approaches separately in detail.
Note: all examples will be leaving out interaction with view, handling of authorization, dealing with dependencies of service factory and other specifics
Injection of factory
The simplified part of bootstrap stage, which deals with kicking off stuff to the controller, would look kinda like this
$request = //... we do something to initialize and route this
$resource = $request->getParameter('controller');
$command = $request->getMethod() . $request->getParameter('action');
$factory = new ServiceFactory;
if ( class_exists( $resource ) ) {
$controller = new $resource( $factory );
$controller->{$command}( $request );
} else {
// do something, because requesting non-existing thing
}
This approach provides a clear way for extending and/or substituting the model layer related code simply by passing in a different factory as the dependency. In controller it would look something like this:
public function __construct( $factory )
{
$this->serviceFactory = $factory;
}
public function postLogin( $request )
{
$authentication = $this->serviceFactory->create( 'Authentication' );
$authentication->login(
$request->getParameter('username'),
$request->getParameter('password')
);
}
This means, that, to test this controller's method, you would have to write a unit-test, which mock the content of $this->serviceFactory, the created instance and the passed in value of $request. Said mock would need to return an instance, which can accept two parameter.
Note: The response to the user should be handled entirely by view instance, since creating the response is part of UI logic. Keep in mind that HTTP Location header is also a form of response.
The unit-test for such controller would look like:
public function test_if_Posting_of_Login_Works()
{
// setting up mocks for the seam
$service = $this->getMock( 'Services\Authentication', ['login']);
$service->expects( $this->once() )
->method( 'login' )
->with( $this->equalTo('foo'),
$this->equalTo('bar') );
$factory = $this->getMock( 'ServiceFactory', ['create']);
$factory->expects( $this->once() )
->method( 'create' )
->with( $this->equalTo('Authentication'))
->will( $this->returnValue( $service ) );
$request = $this->getMock( 'Request', ['getParameter']);
$request->expects( $this->exactly(2) )
->method( 'getParameter' )
->will( $this->onConsecutiveCalls( 'foo', 'bar' ) );
// test itself
$instance = new SomeController( $factory );
$instance->postLogin( $request );
// done
}
Controllers are supposed to be the thinnest part of the application. The responsibility of controller is: take user input and, based on that input, alter the state of model layer (and in rare case - current view). That's it.
With DI container
This other approach is .. well .. it's basically a trade of complexity (subtract in one place, add more on others). It also relays on having a real DI containers, instead of glorified service locators, like Pimple.
My recommendation: check out Auryn.
What a DI container does is, using either configuration file or reflection, it determines dependencies for the instance, that you want to create. Collects said dependencies. And passes in the constructor for the instance.
$request = //... we do something to initialize and route this
$resource = $request->getParameter('controller');
$command = $request->getMethod() . $request->getParameter('action');
$container = new DIContainer;
try {
$controller = $container->create( $resource );
$controller->{$command}( $request );
} catch ( FubarException $e ) {
// do something, because requesting non-existing thing
}
So, aside from ability to throw exception, the bootstrapping of the controller stays pretty much the same.
Also, at this point you should already recognize, that switching from one approach to other would mostly require complete rewrite of controller (and the associated unit tests).
The controller's method in this case would look something like:
private $authenticationService;
#IMPORTANT: if you are using reflection-based DI container,
#then the type-hinting would be MANDATORY
public function __construct( Service\Authentication $authenticationService )
{
$this->authenticationService = $authenticationService;
}
public function postLogin( $request )
{
$this->authenticatioService->login(
$request->getParameter('username'),
$request->getParameter('password')
);
}
As for writing a test, in this case again all you need to do is provide some mocks for isolation and simply verify. But, in this case, the unit testing is simpler:
public function test_if_Posting_of_Login_Works()
{
// setting up mocks for the seam
$service = $this->getMock( 'Services\Authentication', ['login']);
$service->expects( $this->once() )
->method( 'login' )
->with( $this->equalTo('foo'),
$this->equalTo('bar') );
$request = $this->getMock( 'Request', ['getParameter']);
$request->expects( $this->exactly(2) )
->method( 'getParameter' )
->will( $this->onConsecutiveCalls( 'foo', 'bar' ) );
// test itself
$instance = new SomeController( $service );
$instance->postLogin( $request );
// done
}
As you can see, in this case you have one less class to mock.
Miscellaneous notes
Coupling to the name (in the examples - "authentication"):
As you might have notices, in both examples your code would be coupled to the name of service, which was used. And even if you use configuration-based DI container (as it is possible in symfony), you still will end up defining name of the specific class.
DI containers are not magic:
The use of DI containers has been somewhat hyped in past couple years. It is not a silver bullet. I would even go as far as to say that: DI containers are incompatible with SOLID. Specifically because they do not work with interfaces. You cannot really use polymorphic behavior in the code, that will be initialized by a DI container.
Then there is the problem with configuration-based DI. Well .. it's just beautiful while project is tiny. But as project grows, the configuration file grows too. You can end up with glorious WALL of xml/yaml configuration, which is understood by only one single person in project.
And the third issue is complexity. Good DI containers are not simple to make. And if you use 3rd party tool, you are introducing additional risks.
Too many dependencies:
If your class has too many dependencies, then it is not a failure of DI as practice. Instead it is a clear indication, that your class is doing too many things. It is violating Single Responsibility Principle.
Controllers actually have (some) logic:
The examples used above were extremely simple and where interacting with model layer through a single service. In real world your controller methods will contain control-structures (loops, conditionals, stuff).
The most basic use-case would be a controller which handles contact form with as "subject" dropdown. Most of the messages would be directed to a service that communicates with some CRM. But if user pick "report a bug", then the message should be passed to a difference service which automatically create a ticket in bug tracker and sends some notifications.
It's PHP Unit:
The examples of unit-tests are written using PHPUnit framework. If you are using some other framework, or writing tests manually, you would have to make some basic alterations
You will have more tests:
The unit-test example are not the entire set of tests that you will have for a controller's method. Especially, when you have controllers that are non-trivial.
Other materials
There are some .. emm ... tangential subjects.
Brace for: shameless self-promotion
dealing with access control in MVC-like architecture
Some frameworks have nasty habit of pushing the authorization checks (do not confuse with "authentication" .. different subject) in the controller. Aside from being completely stupid thing to do, it also introduces additional dependencies (often - globally scoped) in the controllers.
There is another post which uses similar approach for introducing non-invasive logging
list of lectures
It's kinda aimed at people who want to learn about MVC, but materials there are actually for general education in OOP and development practices. The idea is that, by the time when you are done with that list, MVC and other SoC implementations will only cause you to go "Oh, this had a name? I thought it was just common sense."
implementing model layer
Explains what those magical "services" are in the description above.
I have tried this from http://culttt.com/2013/07/15/how-to-structure-testable-controllers-in-laravel-4/
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.
What should I be testing in my Controller?
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.
An example of bad practice
As a way of illustrating what I’m trying to avoid, here is an example of a Controller method:
public function index()
{
return User::all();
}
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.
Dependency Injection to the rescue
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.
Automatic Resolution
Laravel 4 has a beautiful way of handling Dependancy 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.
Injecting the database into a Controller
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()
{
return User::all();
}
I did:
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
return $this->user->all();
}
When the 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 $this->user instance.
Mocking the database in your Controller tests
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:
<?php
class UserControllerTest extends TestCase {
}
Mocking with Mockery
If you remember back to my post, What is Test Driven Development?, I talked about Mocks as being, a replacement for dependent objects.
In order to create Mocks for the tests in Cribbb, I’m going to use a fantastic package called Mockery.
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 composer.json file:
"require-dev": {
"mockery/mockery": "dev-master"
}
Next, install the package:
composer install --dev
Setting up Mockery
Now to set up Mockery, we have to create a couple of set up methods in the test file:
public function setUp()
{
parent::setUp();
$this->mock = $this->mock('Cribbb\Storage\User\UserRepository');
}
public function mock($class)
{
$mock = Mockery::mock($class);
$this->app->instance($class, $mock);
return $mock;
}
The setUp() method is run before any of the tests. Here we are grabbing a copy of the UserRepository and creating a new mock.
In the mock() method, $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.
Writing your first Controller test
Next you can write your first Controller test:
public function testIndex()
{
$this->mock->shouldReceive('all')->once();
$this->call('GET', 'user');
$this->assertResponseOk();
}
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.
Conclusion
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.
may this help you.
Aspect-Oriented Programming can give your solution for mocking methods even with Service Locator pattern. Look for the AspectMock testing framework.
Github: https://github.com/Codeception/AspectMock
Video by Jeffrey Way: http://jeffrey-way.com/blog/2013/07/24/aspectmock-is-pretty-neat/