如何在没有完整项目的情况下测试共享的 Symfony 2 Bundle

Posted

技术标签:

【中文标题】如何在没有完整项目的情况下测试共享的 Symfony 2 Bundle【英文标题】:How to test a shared Symfony 2 Bundle without a full project 【发布时间】:2014-08-06 17:47:37 【问题描述】:

当我们现在开始在几个项目中使用 Symfony 2 时,我们发现我们可以在我们的项目之间共享相当多的代码。所以我们开始将特性提取到 Symfony 2 包中,以便在我们的项目之间共享它们。

虽然我们基本上可以解决问题,但仍有不少问题难以通过 Google 搜索,尤其是在测试共享捆绑包时。

我们提取的第一个小包包含一个 Doctrine 实体、一个自动注入到客户端项目的 DI 容器中的 kernel.event_listener、一个注释、另一个服务和几个命令。基本思想是客户端项目可以用我们的注解来注解它的控制器,event_listener 会在最终调用控制器之前拦截对被注解的控制器的请求并执行一些额外的逻辑(涉及教义实体)。这些命令旨在管理学说实体的数据库条目。

到目前为止,一切都完全按照我们的预期工作,但我们正在努力解决捆绑包的可测试性问题。首先,包含捆绑包的 Git 存储库不包含完整的 Symfony2 项目。这将是矫枉过正,因为我们只是在这里构建一个包,而不是一个完整的应用程序,对吧?

但是我们如何测试事件监听器呢?我们如何测试它是否被注入到 DI 容器中?我们需要一个测试控制器,该控制器将使用我们的特殊注释进行注释,因此我们可以测试我们的事件侦听器是否正确捕获它。该控制器必须仅在测试时可用,并且不得出现在任何客户端应用程序中。

我们如何测试命令?我们需要模拟学说背后的数据库。当我们尝试在简单地用/vendor/autoload.php 引导的 phpunit 测试中执行命令时,我们当然会得到:

致命错误:调用未定义的方法 Symfony\Component\Console\Application::getKernel() 在 /.../vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Command/ContainerAwareCommand.php 在第 3 行

所以感觉就像我们最终需要在我们的包的存储库中使用一个完整的 Symfony2 项目,以便引导整个框架以便最终能够测试我们的组件。当我查看开源 Symfony2 包时,我发现没有一个将整个框架签入到他们的 Git 存储库中,所以这仍然是错误的。

我错过了什么?我是否缺少有关仅捆绑/无应用程序捆绑开发的文档?

编辑:

我在这里找到了命令测试的解决方案: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;
    

我猜控制器测试必须以类似的、大量模拟的方式工作。当我找到它的解决方案时,我会在这里发布一个完整的答案......

【问题讨论】:

我不是真正的专家(没有太多时间进行实验和太多工作),但我认为您只需要框架包、控制台、http-kernel 等依赖项的子集即可设置并运行您的测试。 也许你的编辑应该是一个答案......无论如何,好的起点。谢谢! 【参考方案1】:

这个问题很老了,但我只是偶然发现了它。

Bundles 是一种 Symfony 特定的方式来共享整个库,包括。它们各自的依赖注入容器配置。

因此,bundle 依赖于 Symfony 内核,如果一个 bundle 依赖于另一个 bundle,就会产生严重的依赖关系,这会有效地阻止单元测试:要测试 bundle A 中的一个单元(一个类),你需要 bundle B 加上Symfony 内核。

您仍然可以进行测试,但生成的测试是验收/集成测试,不再是单元测试。正如您已经注意到的那样,它们不适合测试驱动开发,缓慢且脆弱。

更新

我刚刚写了一篇关于此的博客文章: https://lastzero.net/2015/11/dependent-symfony-2-bundles-and-testability/

【讨论】:

以上是关于如何在没有完整项目的情况下测试共享的 Symfony 2 Bundle的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有完整安装 Tomcat 的情况下运行 Spring Web 应用程序?

如何在没有 Maven 的情况下同时运行 Eclipse Java 项目的所有 JUnit 测试?

如何在没有 SSH 的情况下在 GoDaddy 共享主机中托管 Laravel 5.2?

如何强制 cmake 在没有完整路径的情况下使用 cl.exe?

在没有 Windows 访问权限的情况下使用凭据信息访问共享文件夹

您如何在没有用户共享/授予权限的情况下使用核心位置?