31

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);
j0k
  • 22,600
  • 28
  • 79
  • 90
vishal
  • 3,993
  • 14
  • 59
  • 102

4 Answers4

66

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.

Cyprian
  • 11,174
  • 1
  • 48
  • 45
  • 3
    Emphase on the "you need to pass it to the client's container (not the one from kernel)". – magnetik Jul 28 '15 at 13:05
  • 2
    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. – Rvanlaak May 19 '16 at 09:34
  • 1
    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. – Cyprian May 23 '16 at 08:55
6

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);
Sven
  • 69,403
  • 10
  • 107
  • 109
4

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');
0

Have you tried ?

$serviceA = $this->getMock('ServiceA', array('getRequest'), array(), '', false);
adam187
  • 3,193
  • 21
  • 15