首页 > 解决方案 > 使用 PHP-DI 注入模拟对象以使用 PHPUnit 测试控制器

问题描述

我已经按照“最佳实践”中的建议重构了一些控制器,以通过属性注入使用依赖注入:

final class ZebraController extends Controller
{
    /**
     * @Inject
     * @var AnimalClientInterface
     */
    private $animalsRestClient;

    public function fetchAllZebras(ServerRequestInterface $req): ResponseInterface {
        // ...
    }
}

我的 PHP-DI 配置被配置为注入AnimalClient对象的实例AnimalClientInterface,这在实现代码中很好,因为只有 1 个 real AnimalClient

在我的单元测试中,我需要将 aMockZebraClient注入此属性。我不能像我那样简单地配置它,AnimalClient因为其他类可能被类似地注释但需要,例如,MockTigerClient用于测试。

这是我的单元测试:

class ZebraControllerTest extends TestCase
{
    /** @var ZebraController */
    protected $object;

    public function testFetchAllZebras(): void {
        // assertions here
    }
}

我认为使用该injectOn方法是解决此问题的正确方法,但我不知道如何配置容器以选择正确的模拟对象进行正确的测试。

由于遗留代码结构,构造函数注入是不可能的。应用程序中的所有控制器都需要重构以使用 DI 来更改Controller.

标签: phpunit-testingdependency-injectionphpunitphp-di

解决方案


也许有一个 PHP-DI 特定的答案,但我不熟悉它。在您的情况下,似乎也不允许定义构造函数。鉴于此,您可以使用静态假装构造函数进行测试,它允许访问设置内部状态:

<?php
class A {
    private $b;

    public static function construct($b) {
        $a = new A();
        $a->b = $b;
        return $a;
    }
}

class B {

}

$a = A::construct(new B());
var_dump($a);

回报:

对象(A)#2 (1) { ["b":"A":private]=> 对象(B)#1 (0) { } }


推荐阅读