我最近在学习 Symfony 3 框架和依赖注入。
我希望您帮助我解决我对使用 PHPUnit 在Symfony 3中测试服务的方法的疑虑。我有一些担心如何正确地做到这一点。
让我们举一个服务类:
的例子// src/AppBundle/Services/MathService.php
namespace AppBundle\Services;
class MathService
{
public function subtract($a, $b)
{
return $a - $b;
}
}
我看到通常Symfony中的UnitTest类测试控制器。
但是,我可以测试服务等独立类(例如包含业务逻辑)而不是控制器?
我知道至少有两种方法可以做到:
1。创建一个测试类,在某些方法中扩展 PHPUnit_Framework_TestCase
和创建服务的对象或构造函数在此测试类中(与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
以访问内核。它将使我们能够从内核使用容器注入我们的服务(基于有关testing Doctrine的Symfony文档)。
服务容器的配置:
# app/config/services.yml
services:
app.math:
class: AppBundle\Services\MathService
现在我们的测试类将如下所示:
// 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);
}
}
当我们选择这种方式时会有好处。
首先,我们可以通过依赖注入访问控制器中的服务容器和测试。
其次 - 如果将来我们想要更改服务类的位置或更改类的名称 - 与 1。案例 - 我们可以避免更改许多文件,因为我们至少会在 services.yml
文件中更改路径/名称。
我的问题:
答案 0 :(得分:3)
使用棘手的Symfony 3.4 / 4.0解决方案更新2018年。
此方法with all its pros/cons is described in this post with code examples。
访问私有服务的最佳解决方案是添加编译器通行证,使所有服务公开以进行测试。
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());
}
}
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进行测试等)。
然后您的所有测试都会按预期继续工作!