Mocking Doctrine 2 Entities in PHPUnit with Zend 2

In this article we're going to be looking at how to mock the Doctrine entity manager and entities in unit tests using PHPUnit. While this code should transferable, the examples are demonstrated within Zend 2 framework unit tests.

Why mock doctrine entites?

The purpose of mocking in PHPUnit is to allow you to test specific pieces of code without also testing all the dependencies. With Doctrine though, chances are if you're testing some code referencing a Doctrine entity, that the entity probably already exists - so why not just use it as is, or if not, just write it?

To start with, we wouldn't be exclusively testing one piece of code - we'd also be testing the entity itself (breaking the unit testing rule of testing one thing at a time). Another problem is that by using actual entities the tests will be making lots of database calls. For a compete test suite covering your whole application, this is going to result in a lot of sql queries that will massively slow down the testing process.

So, we mock.

Configuring PHPUnit with Zend 2

I won't run through the entire process of installing and configuring PHPUnit with Zend 2 here as I've already covered that in a previous article Unit Testing with PHPUnit and Zend 2. However as a reference point, here are the bootstrap and PHPUnit configuration files that I have in my 'tests' folder in the root of the application. My test files I'll reference later are stored inside a 'test' folder that mimicks the structure of the 'src' directory within the individual module I'm testing, again check the previous article if anything of this isn't making sense. 

Bootstrap.php

<?php
namespace ApplicationTest;

use Zend\Mvc;
use Zend\ServiceManager\ServiceManager;
use Zend\Mvc\Service\ServiceManagerConfig;

class bootstrap
{
    static $serviceManager;

    static function go()
    {
        // Make everything relative to the root
        chdir(dirname(__DIR__));

        // Setup autoloading
        require_once( __DIR__ . '/../init_autoloader.php' );

        // Run application
        $config = require('config/application.config.php');
        \Zend\Mvc\Application::init($config);

        $serviceManager = new ServiceManager(new ServiceManagerConfig());
        $serviceManager->setService('ApplicationConfig', $config);
        $serviceManager->get('ModuleManager')->loadModules();

        self::$serviceManager = $serviceManager;
    }

    static public function getServiceManager()
    {
        return self::$serviceManager;
    }
}

bootstrap::go();

...and here is the phpunit.xml file also located in the tests folder:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="Bootstrap.php">
    <testsuites>
        <testsuite name="cs">
            <directory>../module/</directory>
        </testsuite>
   </testsuites>
</phpunit>

Mocking the Doctrine Entity Manager and Entities

For demonstration purposes here is a 'User Service' that we'll be testing. The User Service sits inside a module 'test' > 'Application' > 'Service' directory, and a corresponding test file (UserServiceTest.php) would sit inside the 'test' directory with the same sub-directories (we'll get to that).

An example service

<?php
namespace Application\Service;

class UserService extends ServiceBaseAbstract
{
    /**
     * Test function for unit testing
     * @param $userId
     * @return string
     */
    public function getUserById( $userId )
    {
        $user = $this->em->find('Application\Entity\User',  $userId );
        return $user
    }
 }

So all this service currently has is a findUser method which attempts to find a user by the id passed in, and then returns that user. 

This service extends the following ServiceBaseAbstract:

<?php
namespace Application\Service;

/**
 * Class ServiceBaseAbstract
 * Abstract base class for all services
 * @package Application\Service
 */
class ServiceBaseAbstract
{
    // Doctrine Entity Manager
    protected $em;
    // Service Manageer
    protected $sm;

    public function __construct( $sm, $em )
    {
        // Make the service manager available to all services
        $this->sm = $sm;
        // Make the entity manager available to all services
        $this->em = $em;
    }
}

Notice how the Service Manager and Entity Manager are injected, this is achieved in the module.php file (e.g. for the 'application' module in this example), by adding the getServiceConfig method. This process is documented in the article Unit Testing with Zend 2 and PHPUnit.


    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'UserService' =>  function($sm)
                {
                    $em = $sm->get('Doctrine\ORM\EntityManager');
                    return new \Application\Service\UserService($sm, $em);
                }
            ),
        );
    }

So now we've got a demo service to test, let's move onto the actual tests themselves...

Example Doctrine Test

The following test is designed to check that our getUserById function will a) return a valid Doctrine user entity b) check that it returns our dummy user version, thus it hasn't actually had to make any database calls for the test:

<?php
namespace ApplicationTest\Service;
use Application\Service;
use ApplicationTest\Bootstrap;
use PHPUnit_Framework_TestCase;

class UserTest extends \PHPUnit_Framework_TestCase
{
    protected $serviceManager;
    protected $userService;

    protected function setUp()
    {
        $this->serviceManager = Bootstrap::getServiceManager();
    }

    public function testCanGetUserById()
    {
        // Create a dummy user entity
        $user = new \Application\Entity\User();
        $user->id = 123;
        $user->username = 'david';

        // Mock the entity manager, find should return our dummy user
        $emMock = $this->getMock('EntityManager',
            array('getRepository', 'getClassMetadata', 'persist', 'flush', 'find'), array(), '', false);
        $emMock->expects( $this->any() )
            ->method( 'find' )
            ->will( $this->returnValue( $user ) );

        // Create a new instance of the user service injecting our mocked entity manager
        $userService = new \Application\Service\UserService($this->serviceManager, $emMock);

        // Call the service requesting user 123
        $responseUser = $userService->getUserById( 123 );

        // Check the response is a user entity
        $this->assertInstanceOf('Application\Entity\User', $responseUser);

        // Check that the returned entity is our dummy user
        $this->assertEquals('david', $responseUser->username);
    }
}

Let's break this down... Firstly we create a user entity, and populate it with some dummy data. Next we mock the entity manager, and tell it to return our dummy user entity when the find method is called. Finally to do the actual test, we get an instance of the user service with the injected entity manger, call the getUserById method and verify the response is the right type, and that the data matched our dummy.

The result - a tested service using Doctrine without any database calls.

Mocking repositories

So the mocking starts to stack up a little more when you also need to mock the repositories. In the next example we want test the following code that sits within the user service:

public function getUsers()
{
        $users = $this->em->getRepository('Application\Entity\User')->findAll();
        return $users;
}

So a simple method to get all our users via the user repository. Here's the code to achive this as a unit test, commented at each step:

public function testCanGetUsers()
{
        // Create dummy user entities
        $user1 = new \Application\Entity\User();
        $user1->id = 1;
        $user1->username = 'david';

        $user2 = new \Application\Entity\User();
        $user2->id = 2;
        $user2->username = 'james';

        // Put them into a result set
        $users = array( $user1, $user2 );

        // Mock the repository, disabling the constructor
        $userRepositoryMock = $this->getMockBuilder('Application\Entity\Repository\UserRepository')
            ->disableOriginalConstructor()
            ->getMock();
        $userRepositoryMock->expects( $this->once() )
            ->method( 'findAll' )
            ->will( $this->returnValue( $users ) );

        // Mock the entity manager
        $emMock = $this->getMock('EntityManager',
            array('getRepository'), array(), '', false);
        $emMock->expects( $this->once() )
            ->method( 'getRepository' )
            ->will( $this->returnValue( $userRepositoryMock ) );

        // Create a new instance of the user service injecting our mocked entity manager
        $userService = new \Application\Service\UserService($this->serviceManager, $emMock);

        // Assert returns array
        $users = $userService->getUsers();
        $this->assertInternalType('array', $users );

        // Assert first user in the array is a doctrine entity
        $user = $users[0];
        $this->assertInstanceOf('Application\Entity\User', $user);
}

So with the above test we've managed to get user entities, via the repository, via the entity manager, still all without making any database queries to keep our tests running fast.

Sign Up

NEXT: Unit Testing with Zend 2 and PHPUnit

In this article we'll be taking a look at how to integrate PHPUnit with Zend 2 and how to run some simple tests against services and controllers.

comments powered by Disqus
Sign Up

Popular Tags

350x250

Need a web developer?

If you'd like to work with code synthesis on your next project get in touch via the contact page.