【问题标题】:Elegant way to testing the Services/Service Containers in Symfony3 with PHPUnit使用 PHPUnit 在 Symfony3 中测试服务/服务容器的优雅方法
【发布时间】:2016-11-18 22:56:58
【问题描述】:

我最近在学习 Symfony 3 框架和 依赖注入

希望您能帮我解决我对使用 PHPUnit 在 Symfony 3 中测试 Services 的方法的疑惑。我有点担心如何正确地做。

让我们举一个Service类的例子:

// src/AppBundle/Services/MathService.php
namespace AppBundle\Services;

class MathService
{
    public function subtract($a, $b)
    {
        return $a - $b;
    }
}

我看到 Symfony 中的 UnitTest 类通常会测试 Controllers

但是我可以用什么来测试像 Services 这样的独立类(例如包含业务逻辑)而不是 Controllers

我知道至少有两种方法可以做到:


1.创建一个扩展PHPUnit_Framework_TestCase的测试类并创建Service对象在一些方法中此测试类中的 strong> 或 构造函数(与 Symfony 文档中关于 testing 的完全一样)

// tests/AppBundle/Services/MathTest.php
namespace Tests\AppBundle\Services;

use AppBundle\Services\MathService;

class MathTest extends \PHPUnit_Framework_TestCase
{
    protected $math;

    public function __construct() {
        $this->math = new MathService();
    }

    public function testSubtract()
    {
        $result = $this->math->subtract(5, 3);
        $this->assertEquals(2, $result);
    }
}

2. 使用依赖注入将我们的​​服务类作为服务容器。然后创建一个扩展 KernelTestCase 的测试类以访问内核。它将使我们能够使用 Container 从内核中注入我们的服务(基于 Symfony 关于testing Doctrine 的文档)。

服务容器的配置:

# app/config/services.yml
services:
    app.math:
        class: AppBundle\Services\MathService

现在我们的 Test Class 将如下所示:

// tests/AppBundle/Services/MathTest.php
namespace Tests\AppBundle\Services;

use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class MathTest extends KernelTestCase
{
    private $math;

    protected function setUp()
    {
        self::bootKernel();

        $this->math = static::$kernel
            ->getContainer()
            ->get('app.math');
    }

    public function testSubtract()
    {
        $result = $this->math->subtract(5, 3);
        $this->assertEquals(2, $result);
    }
}

我们选择这种方式有好处。

首先,我们可以通过依赖注入控制器测试中访问我们的Service Container

其次-如果将来我们想更改服务类位置或更改类的名称-与1. 案例 - 我们可以避免更改许多文件,因为我们至少会在 services.yml 文件中更改路径/名称。


我的问题:

还有其他方法可以在 Symfony 3 中测试服务类吗?哪种方式更好,应该使用?

【问题讨论】:

  • “我看到通常 Symfony 中的 UnitTest 类测试控制器。”然而,你得出了这么奇怪的结论吗?停止过度思考问题,只使用你的第一种方法。并确保您了解单元测试和功能测试之间的区别。

标签: php unit-testing phpunit containers symfony


【解决方案1】:

2018 年更新,带有棘手的 Symfony 3.4/4.0 解决方案。

这种方法with all its pros/cons is described in this post with code examples


访问私有服务的最佳解决方案是添加编译器通行证,将所有服务公开以供测试

1。更新内核

 use Symfony\Component\HttpKernel\Kernel;
+use Symplify\PackageBuilder\DependencyInjection\CompilerPass\PublicForTestsCompilerPass;

 final class AppKernel extends Kernel
 {
     protected function build(ContainerBuilder $containerBuilder): void
     {
         $containerBuilder->addCompilerPass('...');
+        $containerBuilder->addCompilerPass(new PublicForTestsCompilerPass());
     }
 }

2。要求或创建自己的编译器通行证

PublicForTestsCompilerPass 的样子:

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

final class PublicForTestsCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $containerBuilder): void
    {
        if (! $this->isPHPUnit()) {
            return;
        }

        foreach ($containerBuilder->getDefinitions() as $definition) {
            $definition->setPublic(true);
        }

        foreach ($containerBuilder->getAliases() as $definition) {
            $definition->setPublic(true);
        }
    }

    private function isPHPUnit(): bool
    {
        // defined by PHPUnit
        return defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__');
    }
}

要使用这个类,只需通过以下方式添加包:

composer require symplify/package-builder

当然,更好的方法是使用满足您需求的自己的类(您可以使用 Behat 进行测试等)。

那么您的所有测试将继续按预期工作!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 2020-11-03
    • 1970-01-01
    相关资源
    最近更新 更多