如何在功能测试中模拟Symfony 2服务?

31

我有一个symfony服务,其中一些方法使用redis连接,而另一些方法则不使用。

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
}

我正在为使用只有getRequest方法的代码编写功能测试(此方法不需要redis连接),但由于构造函数将连接作为参数,当我运行测试时,它会尝试连接redis服务器。

我该如何编写模拟服务,完全不使用redis连接并忽略原始构造函数?

我尝试了下面提到的方法,但没有成功。即使我禁用了原始构造函数,它仍然尝试连接redis。

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);
4个回答

66

在创建 ServiceA 的模拟之后,你需要将其传递给客户端的容器(而不是内核的容器,因为客户端对象构建自己的内核)。尝试以下操作:

创建ServiceA模拟后,将其传递给客户端容器(而不是内核容器,因为客户端对象会构建自己的内核)。

$client = self::createClient();

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

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

请注意,每次发出请求时都必须注入此模拟服务。这是因为客户端在每两个请求之间重建内核。


3
强调“你需要将它传递给客户端容器(而不是内核的容器)”。 - magnetik
2
$client->getContainer()->set('my_bundle.service.a', $serviceA) 这段代码是否意味着 $container->get() 不再实例化服务?我们想要“覆盖”该服务,但仍希望容器在之后注入该服务的依赖项。 - Rvanlaak
1
不会再实例化服务了,一旦您使用“set”方法设置对象。您需要自己处理它。 - Cyprian

6

你不应该嘲笑你的被测试类,而是应该嘲笑Redis类并将其注入。

如果这个测试中没有使用Redis,你甚至不需要配置模拟对象。

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

4

0

你试过了吗?

$serviceA = $this->getMock('ServiceA', array('getRequest'), array(), '', false);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接