Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 2.8 : inject mocked repository in a test controller

I try to create a test for a custom controller. In this one, this is what is executed:

Code

$users = $this->getDoctrine()
                ->getRepository('MyBundle:User')
                ->findAllOrderedByName();

In the test controller, this is what I am doing:

$entityManager = $this
            ->getMockBuilder('Doctrine\ORM\EntityManager')
            ->setMethods(['getRepository', 'clear'])
            ->disableOriginalConstructor()
            ->getMock();

        $entityManager
            ->expects($this->once())
            ->method('getRepository')
            ->with('MyBundle:User')
            ->will($this->returnValue($userRepositoryMock));


        // Set the client
        $client = static::createClient();
        $client->getContainer()->set('doctrine.orm.default_entity_manager', $entityManager);

Problem

But at the end the test fails because my mock seems to no be used:

tests\MyBundle\Controller\ListingControllerTest::testAllAction Expectation failed for method name is equal to string:getRepository when invoked 1 time(s). Method was expected to be called 1 times, actually called 0 times.

Any idea ?

EDIT

Following remarks on comments, I created a service:

services:
    my.user.repository:
        class:   MyBundle\Entity\UserRepository
        factory: ['@doctrine.orm.default_entity_manager', getRepository]
        arguments:
          - MyBundle\Entity\User

So now, I "just" have to mock the repo:

$userRepositoryMock = $this->getMockBuilder('MyBundle\Entity\UserRepository')
            ->disableOriginalConstructor()
            ->setMethods(['findAllOrderedByName'])
            ->getMock();

        $userRepositoryMock
            ->expects($this->once())
            ->method('findAllOrderedByName')
            ->will($this->returnValue($arrayOfUsers));

and inject it into the container:

$client->getContainer()->set('my.user.repository', $userRepositoryMock);

But I still have the same issue

like image 228
enrico69 Avatar asked Jan 19 '26 13:01

enrico69


1 Answers

Don't inject container/entity manager in the testing class, instead inject doctrine repositories directly. Also, don't create kernel in your test, tests should run fast.

UPDATE 1: The testing service should require repository in constructor. So in your test you are able to replace it with mock. $client = static::createClient() is for testing controllers against the real database with fixtures (functional test). Don't use it for testing services with mocked dependencies (unit test).

UPDATE 2: Example of unit test:

class UserServiceTest extends UnitTestCase
{
    public function test_that_findAllWrapper_calls_findAllOrderedByName()
    {

        //GIVEN
        $arrayOfUsers = [$user1, $user2];

        $userRepo = $this->getMockBuilder('AppBundle\Repository\UserRepository')
            ->disableOriginalConstructor()
            ->getMock();
        $userRepo
            ->expects($this->once())
            ->method('findAllOrderedByName')->willReturn($arrayOfUsers);


        $userService = new UserService($userRepo);

        //WHEN
        $result = $userService->findAllWrapper();

        //THEN
        $this->assertEquals($arrayOfUsers, $result);
    }
}

class UserService {
    private $userRepo;

    public function __construct(UserRepository $repo)
    {
        $this->userRepo = $repo;
    }

    public function findAllWrapper()
    {
        return $this->userRepo->findAllOrderedByName();
    }
}
like image 156
karser Avatar answered Jan 21 '26 07:01

karser