Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 使用嵌套的依赖项和工厂类执行单元测试_Php_Unit Testing_Design Patterns_Phpunit - Fatal编程技术网

Php 使用嵌套的依赖项和工厂类执行单元测试

Php 使用嵌套的依赖项和工厂类执行单元测试,php,unit-testing,design-patterns,phpunit,Php,Unit Testing,Design Patterns,Phpunit,我是单元测试和PHPUnit的新手,但我最近读了很多关于设计模式和独立测试的书,我决定重构我正在开发的应用程序,以摆脱静态类、单例、硬编码依赖项和在全局范围内定义的任何其他内容,希望使其“可测试”这对未来的曼坦来说不是一件痛苦的事,因为这是一个长期的项目 到目前为止,我相信我理解了单元测试背后的理论,但我想知道,在一个将处理对象嵌套依赖关系的任务委托给工厂的场景中,应该如何对所述工厂进行单元测试,还是测试它只是多余的?测试依赖项的“链”是否同步工作的最佳方法是什么 让我举例说明这些问题。假设您有

我是单元测试和PHPUnit的新手,但我最近读了很多关于设计模式和独立测试的书,我决定重构我正在开发的应用程序,以摆脱静态类、单例、硬编码依赖项和在全局范围内定义的任何其他内容,希望使其“可测试”这对未来的曼坦来说不是一件痛苦的事,因为这是一个长期的项目

到目前为止,我相信我理解了单元测试背后的理论,但我想知道,在一个将处理对象嵌套依赖关系的任务委托给工厂的场景中,应该如何对所述工厂进行单元测试,还是测试它只是多余的?测试依赖项的“链”是否同步工作的最佳方法是什么

让我举例说明这些问题。假设您有以下“遗留”代码:

阶级之家{
受保护的材料;
受保护的门;
受保护的$旋钮;
公共函数构造(){
$this->door=新门();
$this->knob=$this->door->getKnob();
$this->material=“stone”;
echo“House material:”.this->material.PHP_EOL.
; 回显“门材质:”.$this->Door->getMaterial().PHP_EOL.“
”; 回显“旋钮材质:”.$this->Knob->getMaterial().PHP_EOL.“
”; } } 班级门{ 受保护的材料; 受保护的$旋钮; 公共函数构造(){ $this->knob=新的knob(); $this->material=“wood”; } 公共函数getKnob(){ 返回$this->knob; } 公共函数getMaterial(){ 返回$this->material; } } 类旋钮{ 受保护的材料; 公共函数构造(){ $this->material=“metal”; } 公共函数getMaterial(){ 返回$this->material; } } $house=新房子();
这(据我所知)不利于单元测试,因此我们用DI+a工厂类替换硬编码依赖项:

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();
阶级之家{
受保护的材料;
受保护的门;
受保护的$旋钮;
公共功能建筑($door){
$this->door=$door;
$this->knob=$this->door->getKnob();
$this->material=“stone”;
echo“House material:”.this->material.PHP_EOL.
; 回显“门材质:”.$this->Door->getMaterial().PHP_EOL.“
”; 回显“旋钮材质:”.$this->Knob->getMaterial().PHP_EOL.“
”; } } 班级门{ 受保护的材料; 受保护的$旋钮; 公共功能结构(旋钮){ $this->knob=$knob; $this->material=“wood”; } 公共函数getKnob(){ 返回$this->knob; } 公共函数getMaterial(){ 返回$this->material; } } 类旋钮{ 受保护的材料; 公共函数构造(){ $this->material=“metal”; } 公共函数getMaterial(){ 返回$this->material; } } 高级住宅工厂{ 公共函数create(){ $旋钮=新旋钮(); $door=新门(旋钮); $house=新房子($door); 归还$house; } } $houseFactory=新的houseFactory(); $house=$houseFactory->create();
现在(而且,据我所知)房子、门和把手都可以通过模拟依赖项进行单元测试。但是:

1) 现在工厂怎么办

我们应该:

  • 不要测试它,因为它还没有任何值得测试的应用程序逻辑,工厂通常都是这样。假设如果房屋、门和把手的独立测试通过,则工厂应无问题
  • 以某种方式重构工厂,即使用类中的函数获取每个实例,这样可以通过PHPUnit重写这些函数以返回模拟对象,以防类中有一些额外的逻辑在将来可能需要进行一些测试
2) 设置同时依赖于多个(非模拟)依赖项的测试是否可行?我知道这在技术上不是单元测试(也许是集成测试?),但我想使用PHPUnit还是完全可行的?考虑到上面的例子,我希望能够建立一个测试,不仅测试房子、门、旋钮和工厂,而且测试真实对象之间相互作用的结果,可能模拟了它们的一些功能,例如处理数据的功能。对于这种测试来说,PHPUnit是一个糟糕的选择吗


提前感谢您抽出时间。我意识到我所做的一些假设可能不正确,因为我显然不是这方面的专家;欢迎并感谢您的更正

工厂就像
new
关键字一样。您是否测试
new
关键字?不,您测试是否可以构造类。但这独立于工厂本身和单元的一部分,因此已经是单元测试的一部分

2) 被称为集成测试。你也可以用PHPUnit来做


编辑-评论中有一些讨论:

就单元测试而言,您可以对工厂进行单元测试,以实现它的目的:返回具体类型、类型或任何类型

这并没有什么错,但通常并没有必要,因为返回类型的构造函数已经在进行单元测试,而且该测试非常简单,只是数据检查,闻起来像是集成测试。此外,如果不能提供依赖项,则那些将工厂中的该类型作为依赖项的类型(以及正在进行单元测试的类型)将导致编译/执行失败。因此,工厂的一切都已经过测试,即使是从双方。如果工厂没有被消耗,那么你就不需要测试它

我建议你创建一个纯TDD风格的工厂,以便公关
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();