Mat*_*leb 8 php containers phpunit unit-testing symfony
我最近在学习Symfony 3框架和依赖注入.
我希望您帮助我解决我对使用PHPUnit在Symfony 3 中测试服务的方法的疑虑.我有一些担心如何正确地做到这一点.
让我们举一个Service类的例子:
// src/AppBundle/Services/MathService.php
namespace AppBundle\Services;
class MathService
{
public function subtract($a, $b)
{
return $a - $b;
}
}
Run Code Online (Sandbox Code Playgroud)
我看到通常Symfony中的UnitTest类测试控制器.
但是,我可以测试像服务这样的独立类(例如包含业务逻辑)而不是控制器?
我知道至少有两种方法可以做到:
1.创建一个测试类,在此测试类中的某些方法或构造函数中扩展PHPUnit_Framework_TestCase和创建 Service对象(与Symfony关于测试的文档完全相同)
// 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);
}
}
Run Code Online (Sandbox Code Playgroud)
2.使用依赖注入将我们的Service类作为服务容器.然后创建一个Test Class,扩展它KernelTestCase以获取对内核的访问权限.它将使我们能够使用来自内核的Container注入我们的服务(基于有关测试Doctrine的 Symfony文档).
服务容器的配置:
# app/config/services.yml
services:
app.math:
class: AppBundle\Services\MathService
Run Code Online (Sandbox Code Playgroud)
现在我们的测试类看起来像:
// 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);
}
}
Run Code Online (Sandbox Code Playgroud)
我们选择这种方式有好处.
首先,我们有机会获得我们的服务容器在控制器和测试,通过依赖注入.
其次-如果将来我们要改变位置的服务类或更改名称类的-相比1的情况下-我们才能避免在许多文件的变化,因为我们至少会在更改路径/名称 services.yml的文件.
我的问题:
使用棘手的 Symfony 3.4/4.0 解决方案在 2018 年更新。
这种方法及其所有优点/缺点在这篇带有代码示例的帖子中进行了描述。
访问私有服务的最佳解决方案是添加一个 Compiler Pass,使所有服务公开进行测试。
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());
}
}
Run Code Online (Sandbox Code Playgroud)
哪里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__');
}
}
Run Code Online (Sandbox Code Playgroud)
要使用这个类,只需通过以下方式添加包:
composer require symplify/package-builder
Run Code Online (Sandbox Code Playgroud)
但是当然,更好的方法是使用满足您需求的自己的类(您迁移 Behat 进行测试等)。
那么您的所有测试将继续按预期工作!
| 归档时间: |
|
| 查看次数: |
4208 次 |
| 最近记录: |