我是单元测试和 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 现在会发生什么?
应该只是:
- 不测试它,因为它还没有任何值得测试的应用程序逻辑,而工厂通常保持这种状态。假设如果房屋、门和旋钮的独立测试通过了工厂应该没问题。
- 以某种方式重构工厂,即使用类中的函数来获取每个实例,这样可以通过 PHPUnit 覆盖这些函数以返回模拟对象,以防万一类中有一些额外的逻辑可以使用一些测试未来。
2)一次设置依赖于多个(非模拟)依赖项的测试是否可行?我知道这在技术上不是单元测试(也许是集成测试?)但我想使用 PHPUnit 仍然完全可行?鉴于上面的示例,我希望能够设置一个测试,不仅可以单独测试 House、Door、Knob 和 HouseFactory,还可以测试真实对象彼此交互的结果,也许还有它们的一些模拟的函数,例如处理数据的函数。PHPUnit 对于这种测试来说是一个糟糕的选择吗?
在此先感谢您的时间。我意识到我所做的一些假设可能不正确,因为我显然不是这方面的专家;欢迎和赞赏更正。