使用PHP-DI注入模拟对象以使用PHPUnit测试控制器

时间:2019-01-21 05:40:33

标签: php unit-testing dependency-injection phpunit php-di

我已经重构了一些控制器,以通过属性注入as recommended in the "best practices"使用依赖注入:

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

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

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

在单元测试中,我需要向该属性中插入MockZebraClient。我不能像配置AnimalClient那样简单地配置它,因为其他类可能会被类似地注释,但是需要例如MockTigerClient进行测试。

这是我的单元测试:

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

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

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

由于遗留代码结构,无法进行构造函数注入。为了更改Controller的构造函数,需要重构应用程序中的所有控制器以使用DI。

1 个答案:

答案 0 :(得分:0)

也许有一个特定于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);

返回:

  

object(A)#2(1){[“” b“:” A“:private] => object(B)#1(0){}}