【问题标题】:Inject mock objects using PHP-DI for testing controllers with PHPUnit使用 PHP-DI 注入模拟对象以使用 PHPUnit 测试控制器
【发布时间】:2019-06-14 11:48:50
【问题描述】:

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

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

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

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

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

这是我的单元测试:

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

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

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

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

【问题讨论】:

  • 不熟悉 PHP-DI,但你总是可以添加一个构造函数并在测试中调用它。
  • @JohnV。不幸的是,由于代码的遗留结构,我无法更改 Controller 构造函数的方法签名。在代码库中的所有控制器都被重构为使用 DI 之前,在子类中覆盖它以添加更多参数也不是一种选择。

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


【解决方案1】:

也许有一个 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) { } }

【讨论】:

    猜你喜欢
    • 2013-01-16
    • 2011-08-08
    • 1970-01-01
    • 2019-11-27
    • 2012-07-16
    • 2014-04-16
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    相关资源
    最近更新 更多