Symfony2:Mocked服务在容器中设置但未被控制器使用(它仍使用原始服务)

时间:2015-06-22 09:45:32

标签: unit-testing symfony containers functional-testing

我正在为控制器编写功能测试。 它使用一个类从第三方网站导入一些数据,为此,我编写了一个我用于Symfony的类,为它设置服务。

现在,在我的功能测试中,我想用一个模拟的服务替换这个服务,将它设置在容器中并在我的功能测试中使用它。

所以我的代码如下:

    // Mock the ImportDataManager and substitute it in the services container
    $mockDataImportManager = $this->getMockBuilder('\AppBundle\Manager\DataImportManager')->disableOriginalConstructor()->getMock();
    $client->getContainer()->set('shq.manager.DataImport', $mockDataImportManager);

    $client->submit($form);
    $crawler = $client->followRedirect();

据我所知,在每个请求之间,客户端重新启动内核,我必须再次设置模拟类,我在调用$ client-> submit之前立即设置模拟。

但是这种方法对我来说似乎不起作用,控制器仍然继续使用服务的真实版本而不是模拟的服务。

如何在模拟功能测试期间使用模拟类来避免调用远程网站?

如果我转储设置模拟服务,我可以看到它已正确设置:

dump($client->getContainer()->get('shq.manager.DataImport'));die;

返回

.SetUpControllerTest.php on line 145:
Mock_DataImportManager_d2bab1e7 {#4807
  -__phpunit_invocationMocker: null
  -__phpunit_originalObject: null
  -em: null
  -remotes: null
  -tokenGenerator: null
  -passwordEncoder: null
  -userManager: null
}

但是在$form->submit($form)通话期间未使用它,而是使用原始服务。

更新 继续寻找解决方案,我从Symfony项目登陆this GitHub page,用户要求解决我的同一问题。 第二个调用不使用他的类的模拟/替换版本,而是使用原始版本。

这是正确的行为吗?那么,我是否无法在第二次调用客户端时修改服务容器?

1 个答案:

答案 0 :(得分:1)

然而,我不明白为什么服务没有在容器中替代,我也无法真正解决这个问题。

无论如何,我发现了某种解决方法,实际上更正确的解决方案(如果仍然不清楚为什么服务没有被替换,这是我想要解决的好奇心 - 也许是因为$ client-&gt ; submit()方法使用POST方法?)。

我的解决方法是简单的双倍测试。

我在AppBundle/Tests/TestDouble中创建了一个新类,并将其命名为DataImportManagerTestDouble.php

它包含控制器使用的唯一方法:

namespace AppBundle\Tests\TestDouble;

use AppBundle\Entity\User;

class DataImportManagerTestDouble
{
    public function importData(User $user)
    {
        return true;
    }
}

然后,我通过以下方式在config_test.ymlapp/config/config_test.yml)文件中实例化它:

services:
    shq.manager.DataImport:
        class: AppBundle\Tests\TestDouble\DataImportManagerTestDouble

这样,在测试期间,并且仅在测试期间,作为服务加载的类是TestDouble而不是原始类。 所以测试通过,我(相对)高兴。目前,至少。