How does one test that events were dispatched during a function call?
public function updateUser() {
//Do some update stuff
$event = new UserUpdated($user);
$event->attach([
new SendEmailAddressChangeEmail($emailAddress),
new SendEmailAddressChangeEmail($oldEmailAddress),
]);
$event->dispatch();
}
Aside from setting up an email address and seeing if an email is sent, how can I check (using PHP Unit) that the dispatcher is actually dispatching these events? I am assuming that I need to create a mock of some sort, but I am uncertain how to create a mock for a completely unrelated bit of code.
UserUpdated Event code:
class UserUpdated extends BaseEvent
{
public $user;
public function __construct(User $user) {
$this->user = $user;
}
}
and the related SendEmailAddressChanged Handler code:
class SendEmailAddressChangeEmail implements Contracts\HandlerInterface
{
protected $emailAddress;
public function __construct($emailAddress) {
$this->emailAddress = $emailAddress;
}
public function handle($event) {
EmailUtils::sendEmailAddressChangeEmail($this->emailAddress, $event->user->userName, $event->user->userID);
}
}
The updateUser() method you've got does two things in one that especially does not work well with (unit) testing:
business logic
object creation
From your own sense of things I assume this is also what made you ask this question. Often code that is not straight forward to test also is a good canary for design issues, so it is normally best to tackle w/ it.
These two points (1. and 2.) are an over-simplification of what is borrowed from the "Two piles" outlined by Misko Hevery in far more detail in his Clean Code Talks:
For example in "The Clean Code Talks -- Inheritance, Polymorphism, & Testing" from Nov 2008 - https://youtu.be/4F72VULWFvc?t=1328 ("Two Piles" # 22:08)
One solution to make this code more test-able is the use of dependency injection. That is one factory (method) for the user-event and one factory (method) for the object updateUser() is a method of. That concrete type then can make use of the factory object it gets injected to obtain the even object.
In short: If that update-user object needs a user-updated-event object it needs to ask for it in it's constructor.
As you sometimes don't want to create that user-updated-event object beforehand, the alternative is inject an object that knows how to create that user-updated-event object, these kind of objects are called factories.
The test then can inject a factory that presents an event mock object with the expectation that it is dispatched.
A good dispatch library btw. does already provide ready-made mocks for tests but that is out of the scope of Phpunit.
If you don't know yet about the mock functionality of Phpunit, please checkout the product's documentation for it:
Phpunit 7.1 Docs » 9. Test Doubles
Related
I decided to create CreateClassroomService to separte logic in my controller method.
class CreateClassroomService extends Service
{
public function create(string $name, User $user): ?Classroom
{
$this->checkName($name);
$classroom = new Classroom();
$created = $classroom->setName($name)
->associateUser($user)
->save();
return $created ? $classroom : null;
}
private function checkName(string $name): void
{
if (empty($name)) {
throw new InvalidArgumentException();
}
}
}
I am trying to test this service as part of learning unit testing, but I don't know how. I don't know how to mock the classroom object to control what the method should return. Does this mean that creating this service was not a good idea because I am not able to test it? Should I build this service differently? Unless the service can be tested, but I don't know how... What should I check in assertion?
This is my test but it is not good because I am not able to force what should be returned.
public function testGivenCreateCorrectDataClassroomWillBeCreated(): void
{
$name = 'Test classroom';
$user = Mockery::mock(User::class);
$result = $this->service->create($name, $user);
$this->assertTrue($result);
}
For something like this, you could simply assert that the ClassRoom has in fact been created. Docs
As per the docs, update your test class so that it's using the RefreshDatabase trait e.g.:
use Illuminate\Foundation\Testing\RefreshDatabase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
Laravel has Model Factories to make creating models with dummy data very quick and easy. There should already be a UserFactory created for you (you may need to update it if you've updated the default users migration).
public function testGivenCreateCorrectDataClassroomWillBeCreated(): void
{
$name = 'Test classroom';
$user = User::factory()->create();
$result = $this->service->create($name, $user);
$this->assertInstanceOf(ClassRoom::class, $result);
$this->assertDatabaseHas('class_rooms', ['name' => $name]);
}
Don't forget to import the User and ClassRoom models in to your test class.
Not sure how mocking works in Mockery, but lets review what you are doing: your create function that you are trying to test creates a new instance of a Classroom, and since it instantiates the object inline you have no control over it.
From the code you have written, I am assuming that you build a classroom object and return, never using the same creator instance again, so what you can do is add a constructor to CreateClassroomService through which you inject a Classroom object. If you are using the same create service to create multiple classroom objects at a time, you will also need to make sure that you somehow reset the classroom instance to its default state inbetween creation(s), or you inject a fresh & new classroom object before invoking create again. This wholly depends on what the classroom does though.
The classroom object then can be mocked through unit testing -- you inject the mock instance and youre good to go. You actually are already injecting User object, so you're already on the right lines!
class CreateClassroomService extends Service {
private ?Classroom $classroom;
public function __construct(Classroom $classroom) {
$this->classroom = $classroom;
}
...
}
Now you just need to mock your classroom object in your test, inject the mock into your service when instantiating the object, and off you go. :)
Btw I would also say you may want to consider do some more abstraction on your service in the form of interfaces or review your parent class to make it more unit testable in general. Generally speaking for effective unit testing you want to avoid static methods and new keywords; where you can absolutely not avoid it, one approach might be to wrap just that one line of code in an encapsulated method, so you can mock the method instead to return you mock data / mock instances instead (but generally if you have to do this it should be an obvious sign to alert you to having sub-par architecture).
Over the past two years, I have become fairly familiar with PHP MVC style architecture, and have developed all my projects using MVC structures since then.
One question that has continued to bother me is how to group functions and database calls. I run into needing to perform the same actions across models. I would prefer not to duplicate these operations and sql query inside each of the models, but would rather group all user operations into a separate class.
For example, say I have a website with a forum, a blog, and a profile page, each with a separate model, view, and controller. However, say each of these pages needs to perform the same operation to the user table.
My Model class is constructed with a database object automatically. If I need to call a function from the user class, is it ok to pass the db object to that new User class? ... to do something like the following? I am not sure if passing objects like I am doing is fine, or is there a much better way of setting things up? Am I wasting resources, or is this a clumsy way of doing things?
Profile Model
class Profile_Model extends Model{
public function __construct() {
parent::__construct();
}
public function someFunction(){
$this->db->insert( "SOME SQL" );
$user = new User( $this->db ); // OK TO PASS DB OBJECT LIKE THIS?
$user->setSomething();
}
public function anotherFunction(){
//do something else that does not need a user object
}
}
User Class
class User{
public function __construct($db){
$this->db = $db; // OK TO SET DB OBJECT AS CLASS VARIABLE AGAIN?
}
public function setSomething(){
$this->db->insert( "SOME SQL" );
}
}
I'm trying to give you a really basic example of how I'd implement this architecture; Since it's really basic and I'm just a passionate developer and nothing more it could be I'm breaking some architectural rules, so please take it as a proof of concept.
LET'S START quickly with the Controller part where you get some request. Now you need someone that takes care of doing the dirty work.
As you can see here I'm trying to pass all the "dependencies" via constructor. These way you should be able to easily replace it with Mocks when testing .
Dependency injection is one of the concepts here.
AND NOW the Model (please remember Model is a layer and not a single class)
I've used "Services (or cases)" that should help you to compose a group of behaviors with all the actors (Classes) involved in this behavior.
Idendifying common behaviours that Services (or Cases) should do, is one of the concepts here.
Keep in mind that you should have a big picture in mind (or somewhere else depending on the project) before starting, in order to respect principle like KISS, SOLID, DRY, etc..
And please pay attention to method naming, often a bad or long name (like mine for example) is a sign that the class has more than a single Responsability or there's smell of bad design.
//App/Controllers/BlogController.php
namespace App\Controllers;
use App\Services\AuthServiceInterface;
use App\Services\BlogService;
use App\Http\Request;
use App\Http\Response;
class BlogController
{
protected $blogService;
public function __construct(AuthServiceInterface $authService, BlogService $blogService, Request $request)
{
$this->authService = $authService;
$this->blogService = $blogService;
$this->request = $request;
}
public function indexAction()
{
$data = array();
if ($this->authService->isAuthenticatedUser($this->request->getSomethingRelatedToTheUser())) {
$someData = $this->blogService->getSomeData();
$someOtherData = $this->request->iDontKnowWhatToDo();
$data = compact('someData', 'someOtherData');
}
return new Response($this->template, array('data' => $data), $status);
}
}
Now we need to create this Service that we've used in the controller. As you can see we're not talking directly with the "storage or data layer" but instead we're calling an abstraction layer that will handle that for us.
Using a Repository Pattern to retrieve data from a data layer, is one of the concepts here.
this way we can switch to whatever repository (inMemory, other storage, etc) to retrieve our data without changing the interface that the Controller is using, same method call but get data from another place.
Design by interfaces and not by concrete classes is one of the concepts here.
//App/Services/BlogService.php
<?php
namespace App\Services;
use App\Model\Repositories\BlogRepository;
class BlogService
{
protected $blogRepository;
public function __construct(BlogRepositoryInterface $blogRepository)
{
$this->blogRepository = $blogRepository;
}
public function getSomeData()
{
// do something complex with your data, here's just simple ex
return $this->blogRepository->findOne();
}
}
At this point we define the Repository that contains the persistance handler and knows about our Entity.
Again decoupling storage Persister and knowledge of an entity (what "can" be coupled with a mysql table for example), is one of the concepts here.
//App/Model/Repositories/BlogRepository.php
<?php
namespace App\Models\Respositories;
use App\Models\Entities\BlogEntity;
use App\Models\Persistance\DbStorageInterface;
class DbBlogRepository extends EntityRepository implements BlogRepositoryInterface
{
protected $entity;
public function __construct(DbStorageInterface $dbStorage)
{
$this->dbStorage = $dbStorage;
$this->entity = new BlogEntity;
}
public function findOne()
{
$data = $this->dbStorage->select('*')->from($this->getEntityName());
// This should be part of a mapping logic outside of here
$this->entity->setPropA($data['some']);
return $this->entity;
}
public function getEntityName()
{
return str_replace('Entity', '', get_class($this->entity));
}
}
At the end a simple entity with Setters and Getters:
//App/Model/Entities/BlogEntity.php
<?php
namespace App\Models\Entities;
class BlogEntity
{
protected $propA;
public function setPropA($dataA)
{
$this->propA = $dataA;
}
public function getPropA()
{
return $this->propA;
}
}
AND NOW? how can you inject this classes passed as dependencies? Well, this is a long answer.
Indicatively you could use Dependency Injection as we've done here have a init/boot file where you define things like:
// Laravel Style
App::bind('BlogRepositoryInterface', 'App\Model\Repositories\DbBlogRepository');
App::bind('DbStorageInterface', 'App\Model\Persistence\PDOStorage');
or some config/service.yml file like:
// Not the same but close to Symfony Style
BlogService:
class: "Namespace\\ConcreteBlogServiceClass"
Or you may feel the need of a Container Class from where you can ask the service you need to use in your controller.
function indexAction ()
{
$blogService = $this->container->getService('BlogService');
....
Dulcis in fundo here are some useful links (You can find tons of docs about this):
Services in Domain-Driven Design
Wicked Domain Model
Dependency Injection Container
Inversion of Control and Dependency Injection
Managing common Dependencies with parent Services
Whenever you need to use an object from another class there is only one safe way to do it: Dependency Injection.
Example:
Instead of having:
public function myMethod(){
$anotherObject = new Object();
}
You should inject the object with the constructor:
function __construct($dependency) {
$this->anotherObject = $dependency;
}
Once you have this structure you can use type hint and an Inversion of Control container to build thing automatically, e.g. define:
function __construct(DependencyInterface $dependency) {
$this->anotherObject = $dependency;
}
And then set your IoC container to inject the right dependency when you need to use this object
Do you use any frameworks? If not, try having a look at some popular ones, like Zend Framework or Symfony. You'll find they solve your problem and probably many more and are a great way to expand your knowledge on how to structure your project.
That aside you are close. Although adding the database directly to your User-model is probably not want you want to do. If you can get Martin Fowler's Patterns of Enterprise Application Architecture (PEAA) you will find a whole chapter outlining how to connect your models to your database. I prefer a Gateway-class (search for the Gateway-pattern or look at Zend_Db) when building something on my own, as it is relatively easy to implement and build.
Basically you have a class which performs queries and then will pass the data to your model. Just look at Data Source Architectural Patterns in Martin Fowler's pattern catalog (http://martinfowler.com/eaaCatalog/) to get a quick glance how to structure it and definitely read the book to get a real understanding when and how to use the patterns.
I hope this helps.
Part of the answer is to use dependency injection, but there is more to it than that. Cognitively speaking, grouping starts in the mind and is teased out better by brainstorming and modeling: Entity Relationship Diagrams and UML Diagrams.
Grouping of methods into classes and delegating tasks to injected objects makes sense, but there is usually room for one level of inheritance (at minimum). The use of abstract super classes and a Strategy Pattern for child classes that inherit base functionality from the abstract parent can help reduce code duplication (DRY).
All that being said, this is one reason why dependency injection containers are popular. They allow you to obtain the objects, and hence functionality, you need anywhere, without coupling object instantiation to usage.
Do a search for Pimple in Google. It may give you some ideas.
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/
I'm new to OOP and thought I'd give Silex a try on a small app I'm attempting. I'm looking for some advice as to whether my design falls in line with good object oriented principles.
I have a User object which is basically just a bunch of properties, getters and setters. I then have a UserService object which will contain the logic for authenticating users, getting a user from the database, setting or updating user information, etc. I also have a UserServiceProvder class which is there to provide an instance of the UserService class to the app (which seems to be the best way to create a reusable chunk of code in Silex).
The question I have now is this: I am using the Doctrine DBAL that ships with Silex and when I instantiate the UserService class, I'm tempted to pass in a reference to the Doctrine object and then hard code calls to that object into methods of the UserService class.
For instance, to return a User from the database by id, I might create a method called getUserById($id) and then hardcode a Doctrine prepared statement into that method to select that user from the database and then return a User object.
Would it be better for me to create a whole other service that is just a further abstraction of the Doctrine DBAL and pass that to UserService when I instantiate it? That way, I could hard code the Doctrine prepared statements into that class, leaving my UserService class more encapsulated and reusable in case I decide to move away from Doctrine in the future.
I guess what I'm having a hard time with is realizing if there is a such a thing as overkill in OOP. It seems to me like the second method is much more reusable, but is it necessary or wise?
Moving the Database access to a separate class will bring you a couple of advantages. First of all, if you keep the database access apart from the rest of your logic you can replace the implementation of your database access more easy. If for a reason you want to drop the Doctrine DBAL you'll be happy that all the code is just referencing some interface to a repository instead of directly querying a database.
A second great advantage is that you can test your application logic in separation of your database access logic. If you inject a Repository for users inside your UserService you can Mock this in your tests and be sure they only fail if something is wrong with the actual application logic.
A small example of what you could do
The interface is convenient for reference throughout your codebase. No code references the implementation, only the interface. That way you can easily replace the implementation of the interface without touching all the places it is used:
interface IUserRepository
{
/**
* #return User
*/
public function getUserById($userId);
}
Of course you do need an implementation of said interface. This is what you inject into your UserService. This is what you one day might replace with another implementation of the interface:
class DoctrineDBALUserRepository implements IUserRepository
{
/**
* #return User
*/
public function getUserById($userId)
{
//implementation specific for Doctrine DBAL
}
}
The UserService only knows about the interface and can use it freely. To avoid having to inject the UserRepository in a lot of places in your code you could create a convenience build method. Notice the constructor that references the interface and the build method that injects an implementation of that interface:
class UserService
{
private $UserRepository;
public static build()
{
return new UserService(new DoctrineDBALUserRepository());
}
public function __construct(IUserRepository $UserRepository)
{
$this->UserRepository = $UserRepository;
}
public function getUserById($userId)
{
if ($User = $this->UserRepository->getUserById($userId) {
return $User;
}
throw new RuntimeException('O noes, we messed up');
}
With this in place you can write tests for the business logic (e.g. throw an exception if saving fails):
public function UserServiceTest extends PHPUnit_Framework_TestCase
{
public function testGetUserById_whenRetrievingFails_shouldThrowAnException()
{
$RepositoryStub = $this->getMock('IUserRepository');
$RepositoryStub->expects($this->any())->method('getUserById')->will($this->returnValue(false);
$UserService = new UserService($RepositoryStub);
$this->setExpectedException('RuntimeException');
$UserService->getUserById(1);
}
}
I can imagine you're not familiar with the last bit of code if you're not into unit-testing yet. I hope you are and if not urge you to read up on that as well :D I figured it was good for the completeness of the answer to include it no matter what.
Why is testing singletons or registry pattern hard in a language like PHP which is request driven?
You can write and run tests aside from the actual program execution, so that you are free to affect the global state of the program and run some tear downs and initialization per each test function to get it to the same state for each test.
Am I missing something?
While it's true that "you can write and run tests aside of the actual program execution so that you are free to affect the global state of the program and run some tear downs and initialization per each test function to get it to the same state for each test.", it is tedious to do so. You want to test the TestSubject in isolation and not spend time recreating a working environment.
Example
class MyTestSubject
{
protected $registry;
public function __construct()
{
$this->registry = Registry::getInstance();
}
public function foo($id)
{
return $this->doSomethingWithResults(
$registry->get('MyActiveRecord')->findById($id)
);
}
}
To get this working you have to have the concrete Registry. It's hardcoded, and it's a Singleton. The latter means to prevent any side-effects from a previous test. It has to be reset for each test you will run on MyTestSubject. You could add a Registry::reset() method and call that in setup(), but adding a method just for being able to test seems ugly. Let's assume you need this method anyway, so you end up with
public function setup()
{
Registry::reset();
$this->testSubject = new MyTestSubject;
}
Now you still don't have the 'MyActiveRecord' object it is supposed to return in foo. Because you like Registry, your MyActiveRecord actually looks like this
class MyActiveRecord
{
protected $db;
public function __construct()
{
$registry = Registry::getInstance();
$this->db = $registry->get('db');
}
public function findById($id) { … }
}
There is another call to Registry in the constructor of MyActiveRecord. You test has to make sure it contains something, otherwise the test will fail. Of course, our database class is a Singleton as well and needs to be reset between tests. Doh!
public function setup()
{
Registry::reset();
Db::reset();
Registry::set('db', Db::getInstance('host', 'user', 'pass', 'db'));
Registry::set('MyActiveRecord', new MyActiveRecord);
$this->testSubject = new MyTestSubject;
}
So with those finally set up, you can do your test
public function testFooDoesSomethingToQueryResults()
{
$this->assertSame('expectedResult', $this->testSubject->findById(1));
}
and realize you have yet another dependency: your physical test database wasn't setup yet. While you were setting up the test database and filled it with data, your boss came along and told you that you are going SOA now and all these database calls have to be replaced with Web service calls.
There is a new class MyWebService for that, and you have to make MyActiveRecord use that instead. Great, just what you needed. Now you have to change all the tests that use the database. Dammit, you think. All that crap just to make sure that doSomethingWithResults works as expected? MyTestSubject doesn't really care where the data comes from.
Introducing mocks
The good news is, you can indeed replace all the dependencies by stubbing or mock them. A test double will pretend to be the real thing.
$mock = $this->getMock('MyWebservice');
$mock->expects($this->once())
->method('findById')
->with($this->equalTo(1))
->will($this->returnValue('Expected Unprocessed Data'));
This will create a double for a Web service that expects to be called once during the test with the first argument to method findById being 1. It will return predefined data.
After you put that in a method in your TestCase, your setup becomes
public function setup()
{
Registry::reset();
Registry::set('MyWebservice', $this->getWebserviceMock());
$this->testSubject = new MyTestSubject;
}
Great. You no longer have to bother about setting up a real environment now. Well, except for the Registry. How about mocking that too. But how to do that. It's hardcoded so there is no way to replace at test runtime. Crap!
But wait a second, didn't we just say MyTestClass doesn't care where the data comes from? Yes, it just cares that it can call the findById method. You hopefully think now: why is the Registry in there at all? And right you are. Let's change the whole thing to
class MyTestSubject
{
protected $finder;
public function __construct(Finder $finder)
{
$this->finder = $finder;
}
public function foo($id)
{
return $this->doSomethingWithResults(
$this->finder->findById($id)
);
}
}
Byebye Registry. We are now injecting the dependency MyWebSe… err… Finder?! Yeah. We just care about the method findById, so we are using an interface now
interface Finder
{
public function findById($id);
}
Don't forget to change the mock accordingly
$mock = $this->getMock('Finder');
$mock->expects($this->once())
->method('findById')
->with($this->equalTo(1))
->will($this->returnValue('Expected Unprocessed Data'));
and setup() becomes
public function setup()
{
$this->testSubject = new MyTestSubject($this->getFinderMock());
}
Voila! Nice and easy and. We can concentrate on testing MyTestClass now.
While you were doing that, your boss called again and said he wants you to switch back to a database because SOA is really just a buzzword used by overpriced consultants to make you feel enterprisey. This time you don't worry though, because you don't have to change your tests again. They no longer depend on the environment.
Of course, you still you have to make sure that both MyWebservice and MyActiveRecord implement the Finder interface for your actual code, but since we assumed them to already have these methods, it's just a matter of slapping implements Finder on the class.
And that's it. Hope that helped.
Additional Resources:
You can find additional information about other drawbacks when testing Singletons and dealing with global state in
Testing Code That Uses Singletons
This should be of most interest, because it is by the author of PHPUnit and explains the difficulties with actual examples in PHPUnit.
Also of interest are:
TotT: Using Dependency Injection to Avoid Singletons
Singletons are Pathological Liars
Flaw: Brittle Global State & Singletons
Singletons (in all OOP languages, not just PHP) make a particular kind of debugging called unit testing difficult for the same reason that global variables do. They introduce global state into a program, meaning that you can't test any modules of your software that depend on the singleton in isolation. Unit testing should include only the code under test (and its superclasses).
Singletons are essentially global state, and while having global state can make sense in certain circumstances, it should be avoided unless it's necessary.
When finishing a PHP test, you can flush singleton instance like this:
protected function tearDown()
{
$reflection = new ReflectionClass('MySingleton');
$property = $reflection->getProperty("_instance");
$property->setAccessible(true);
$property->setValue(null);
}