PHPUnit - 我的理解是无法使用模拟对象来测试依赖注入容器,这正确吗?

3

我正在进行一个依赖注入容器的单元测试。

在最基本的层面上,我正在测试对象图的创建是否正确。这需要使用反射和加载到DIC中的规则的混合。

DIC使用类定义工作,由于mock的无依赖性质,我认为它们不适合这个任务,我的想法正确吗?

以下是一个没有使用mock的测试样例:

public function testObjectGraphCreation() {
    $a = $this->dic->create('A');
    $this->assertInstanceOf('B', $a->b);
    $this->assertInstanceOf('C', $a->b->c);
    $this->assertInstanceOf('D', $a->b->c->d);
    $this->assertInstanceOf('E', $a->b->c->e);
    $this->assertInstanceOf('F', $a->b->c->e->f);
} 

显然,这种链接和公共依赖项仅用于测试。

我定义了几个类来使其工作:

class A {
    public $b;

    public function __construct(B $b) {
        $this->b = $b;
    }
}

class B {
    public $c;

    public function __construct(C $c) {
        $this->c = $c;
    }
}

class C {
    public $d;
    public $e;

    public function __construct(D $d, E $e) {
        $this->d = $d;
        $this->e = $e;
    }
}


class D {

}
class E {
    public $f;
    public function __construct(F $f) {
        $this->f = $f;
    }
}

class F {}

由于这个测试的性质,我是否正确地认为我不能使用生成的模拟数据?
2个回答

1

这更像是一个整合测试,您正在一次性测试整个 DI 系统。相反,请看看您可以模拟系统的哪些部分--而不是它创建的对象。我无法根据未知的类做出有根据的猜测。

虽然您可能无法使用 PHPUnit 的模拟对象,但您可以自己创建同样功能的一次性模拟。例如,为了通过调用从容器中获取的值设置属性 Database::setPassword 来进行测试,您需要创建一个模拟的 Database 类,将密码放入容器中,并要求容器创建对象。

class MockDatabase {
    public $passwordSet = false;
    public function setPassword($password) {
        if ($password != 'password') {
            throw new InvalidArgumentException('Expected "password"');
        }
        $this->passwordSet = true;
    }
}

...

function testInjectProperty() {
    $container = Container::create(array(
        'password' => 'password',
    ));
    $database = $container->create('MockDatabase');
    self::assertTrue($database->passwordSet);
}

谢谢!这基本上就是我对字母类所做的事情。它们基本上是为测试而存在的模拟类。我不想使用任何真实的东西,因为正如你所说,那么我就要测试那些东西以及DIC。唯一与您示例不同的部分是,在现实世界中,被模拟的类可能还具有依赖关系,这是DIC所需的功能。但是,通过使用公共属性来存储依赖项,我已经在我的简单模拟中考虑到了这一点。 - Tom B

1

你说得对。这段代码很难进行测试。

相反,正确的依赖注入方式是将这些对象注入到需要它们的对象/方法中:

A::__construct(B $b) { $this->b = $b; }

例如。

确实!这就是依赖注入容器所做的事情——自动注入所需的依赖项。但由于我正在测试此功能——即依赖项是否被注入到整个对象图中——我认为生成模拟对象不适用于测试,因为我需要一个真正的对象图来进行测试。 - Tom B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接