当我们现在开始在几个项目中使用Symfony 2时,我们发现在我们的项目中可以分享相当多的代码。因此,我们开始将功能提取到Symfony 2软件包中,以便在我们的项目之间共享它们。
虽然我们基本上已经开始工作了,但仍有很多问题不容易进行,但特别是在测试共享软件包时。
我们提取的第一个小包包含一个Doctrine Entity,一个kernel.event_listener
,它被自动注入客户端项目的DI容器,一个注释,另一个服务和几个命令。基本思想是客户端项目可以使用我们的注释来注释其控制器,event_listener将拦截对注释控制器的请求,并在最终调用控制器之前执行一些额外的逻辑(涉及教义实体)。这些命令用于管理doctrine实体的数据库条目。
到目前为止,一切都完全符合我们的预期,但我们正在努力解决捆绑的可测性问题。首先,保存包的Git存储库不包含完整的Symfony2项目。这样做有点矫枉过正,因为我们只在这里构建一个捆绑包,而不是整个应用程序,对吧?
但是我们如何测试事件监听器呢?我们如何测试它被注入DI容器?我们需要一个测试控制器,它将使用我们的特殊注释进行注释,因此我们可以测试我们的事件监听器是否正确捕获它。该控制器必须在测试时才可用,并且绝不能出现在任何客户端应用程序中。
我们如何测试命令?我们需要模仿学说背后的数据库。当我们尝试在phpunit测试中执行命令时,只需用/vendor/autoload.php
进行自举,当然我们得到:
致命错误:调用未定义的方法 Symfony \ Component \ Console \ Application :: getKernel()in /.../vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Command/ContainerAwareCommand.php 在第3行
所以感觉就像我们最终需要在我们的bundle的存储库中需要一个完整的Symfony2项目才能引导整个框架以最终测试我们的组件。当我查看开源Symfony2软件包时,我发现没有将整个框架检查到他们的Git存储库中,因此仍然感觉不对。
我错过了什么?是否有一篇关于Bundle-Only / Applicationless捆绑开发的文档我不知道了?
我在这里找到了一个命令测试解决方案:http://www.ricardclau.com/2013/02/testing-symfony2-commands-mocking-the-di-container-with-mockery/
事实证明,错误来自ContainerAwareCommand
试图创建一个新容器,这显然不适用于裸测试环境。我通过模拟容器并手动将其注入命令来解决问题,如下所示:
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
class MyCommandTest extends \PHPUnit_Framework_TestCase {
public function testExecute() {
$application = new Application();
$application->add(new MyCommand());
$command = $application->find('my:command');
$command->setContainer($this->getMockContainer()); // <= This avoids ContainerAwareCommand creating a 'real' container in a test env
$commandTester = new CommandTester($command);
$commandTester->execute(array('command' => $command->getName()));
print $commandTester->getDisplay();
$this->assertRegExp('/.../', $commandTester->getDisplay());
}
protected function getMockContainer() {
// Mock the container and everything you'll need here
$mockDoctrine = $this->getMock('Symfony\Bridge\Doctrine\RegistryInterface');
$mockDoctrine->...;
$mockContainer = $this->getMock('Symfony\Component\DependencyInjection\Container');
$mockContainer->expects($this->once())
->method('get')
->with('doctrine')
->willReturn($mockDoctrine);
return $mockContainer;
}
}
我猜控制器测试必须以类似的,模拟重的方式工作。当我找到解决方案时,我会在这里发布一个完整的答案......
答案 0 :(得分:0)
这个问题已经很老了,但我偶然发现了它。
Bundles是Symfony特定的共享整个库的方式。各自的依赖注入容器配置。
因此,bundle依赖于Symfony内核,如果一个bundle依赖于另一个bundle,你会创建大量依赖,这有效地阻止了单元测试:要测试bundle A中的一个单元(一个类),你需要捆绑B加上Symfony内核。
您仍然可以测试,但最终的测试是接受/集成测试,而不是单元测试。正如您已经注意到的那样,这些不适合测试驱动开发,缓慢而脆弱。
<强>更新强>
我刚写了一篇关于此的博文: https://lastzero.net/2015/11/dependent-symfony-2-bundles-and-testability/