3

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

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

DIC 使用类定义工作,并且由于模拟的无依赖性,我认为它们不适合这项任务是否正确?

在不使用模拟的情况下,这是我的一个测试的外观:

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 {}

由于这个测试的性质,我是否认为我不能为此使用生成的模拟?

4

2 回答 2

1

你是对的。这是高度不可测试的代码。

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

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

例如。

于 2012-09-22T11:03:27.280 回答
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);
}
于 2012-09-22T22:18:39.047 回答