【发布时间】:2012-04-25 02:33:06
【问题描述】:
我是单元测试和 PHPUnit 的新手,但我最近阅读了很多关于设计模式和隔离测试的内容,我决定重构我正在开发的应用程序以摆脱静态类、单例、硬编码的依赖项和在全局范围内定义的任何其他内容,希望使其“可测试”,并且将来维护起来不会很麻烦,因为它是一个长期项目。
到目前为止,我相信我了解单元测试背后的理论,但我想知道,在将对象的嵌套依赖关系委托给工厂处理的情况下,应该如何对工厂进行单元测试,或者它只是多余的测试它?测试依赖“链”是否同步运行的最佳方法是什么?
让我来说明问题。假设您有以下“遗留”代码:
class House {
protected $material;
protected $door;
protected $knob;
public function __construct() {
$this->door = new Door();
$this->knob = $this->door->getKnob();
$this->material = "stone";
echo "House material: ".$this->material . PHP_EOL . "<br/>";
echo "Door material: ".$this->door->getMaterial() . PHP_EOL . "<br/>";
echo "Knob material: ".$this->knob->getMaterial() . PHP_EOL . "<br/>";
}
}
class Door {
protected $material;
protected $knob;
public function __construct() {
$this->knob = new Knob();
$this->material = "wood";
}
public function getKnob() {
return $this->knob;
}
public function getMaterial () {
return $this->material;
}
}
class Knob {
protected $material;
public function __construct() {
$this->material = "metal";
}
public function getMaterial () {
return $this->material;
}
}
$house = new House();
这(据我的理解)不利于单元测试,因此我们将硬编码的依赖项替换为 DI + 工厂类:
class House {
protected $material;
protected $door;
protected $knob;
public function __construct($door) {
$this->door = $door;
$this->knob = $this->door->getKnob();
$this->material = "stone";
echo "House material: ".$this->material . PHP_EOL . "<br/>";
echo "Door material: ".$this->door->getMaterial() . PHP_EOL . "<br/>";
echo "Knob material: ".$this->knob->getMaterial() . PHP_EOL . "<br/>";
}
}
class Door {
protected $material;
protected $knob;
public function __construct($knob) {
$this->knob = $knob;
$this->material = "wood";
}
public function getKnob() {
return $this->knob;
}
public function getMaterial () {
return $this->material;
}
}
class Knob {
protected $material;
public function __construct() {
$this->material = "metal";
}
public function getMaterial () {
return $this->material;
}
}
class HouseFactory {
public function create() {
$knob = new Knob();
$door = new Door($knob);
$house = new House($door);
return $house;
}
}
$houseFactory = new HouseFactory();
$house = $houseFactory->create();
现在(再一次,据我了解)House、Door 和 Knob 可以使用模拟依赖项进行单元测试。但是:
1) HouseFactory 现在会发生什么?
应该只是:
- 不测试它,因为它还没有任何值得测试的应用程序逻辑,而且工厂通常保持这种状态。假设如果 House、Door 和 Knob 的独立测试通过了 Factory 应该没问题。
- 以某种方式重构工厂,即使用类中的函数来获取每个实例,这样可以通过 PHPUnit 覆盖这些函数以返回模拟对象,以防万一类中有一些额外的逻辑可以使用将来会进行一些测试。
2) 设置一次依赖多个(非模拟)依赖项的测试是否可行?我知道这在技术上不是单元测试(也许是集成测试?)但我想使用 PHPUnit 仍然完全可行?鉴于上面的示例,我希望能够设置一个测试,不仅可以单独测试 House、Door、Knob 和 HouseFactory,还可以测试真实对象彼此交互的结果,也许还有它们的一些模拟的函数,例如处理数据的函数。 PHPUnit 对于这类测试是不是一个糟糕的选择?
提前感谢您的宝贵时间。我意识到我所做的一些假设可能不正确,因为我显然不是这方面的专家;欢迎和赞赏更正。
【问题讨论】:
标签: php unit-testing design-patterns phpunit