How to mock Symfony 2 service in a functional test?

32,542

Solution 1

After you create ServiceA mock, you need to pass it to client's container (not the one from kernel's because client object builds its own kernel). Try this:

$client = self::createClient();

$serviceA = $this->getMockBuilder('ServiceA')
    ->disableOriginalConstructor()
    ->getMock();

$client->getContainer()->set('my_bundle.service.a', $serviceA);

Pay attention, that you must inject this mocked service every time you make a request. It's because the client rebuilds kernel between each two requests.

Solution 2

You should not mock your tested class, you should mock the Redis class and inject it.

If Redis isn't used for this test, you need not even configure the mock.

$redis = $this->getMockBuilder('Redis')->disableOriginalConstructor()->getMock();
$serviceA = new ServiceA($redis);

Solution 3

There is special tool which takes care of mocked services - https://github.com/ramunasd/symfony-container-mocks

It's easy like that:

$service = static::$kernel->getContainer()->prophesize('my.custom.service');
Share:
32,542
vishal
Author by

vishal

Updated on March 03, 2020

Comments

  • vishal
    vishal about 4 years

    I have symfony service which uses redis connection in some methods but not in all methods.

    class ServiceA
    {
        private $redis;
    
        public function __construct($redis)
        {
            $this->redis = $redis;
        }
    
        public function getRequest($param1, $param2)
        {
        $result = $param1+ $param2;
            return $request;
        }
    
        .. other methods which use $redis connection
    }
    

    I am writing functional test for the code which use only getRequest method (this method does not need redis connection) but as the constructor takes the connection as an argument, when I run test it tried to connect redis server.

    How can I write mock service which does not use redis connection at all and ignore original constructor.

    I am trying approach mentioned below but no success. It still tries to connect redis eventhough I have disabled original constructor.

    http://blog.lyrixx.info/2013/04/12/symfony2-how-to-mock-services-during-functional-tests.html

    $serviceA = $this->getMockBuilder('ServiceA')
        ->disableOriginalConstructor()
        ->getMock();
    
    static::$kernel->getContainer()->set('my_bundle.service.a', $serviceA);
    
  • magnetik
    magnetik almost 9 years
    Emphase on the "you need to pass it to the client's container (not the one from kernel)".
  • Rvanlaak
    Rvanlaak almost 8 years
    Does $client->getContainer()->set('my_bundle.service.a', $serviceA) imply that $container->get() will not instantiate the service anymore? We want to "override" the service but still want the container to inject the service its dependencies afterwards.
  • Cyprian
    Cyprian almost 8 years
    No, it won't instantiate the service anymore once you set the object by "set" method. You need to take care of it by yourself.