如果DI不可行,如何将实例化与单元测试的实现分离?

时间:2018-01-18 01:04:00

标签: php unit-testing phpunit

我有以下代码(此问题的简化和详细信息已更改):

n

在上面的例子中,我必须从add_new_thing方法中解耦Thing_A和Thing_B的实例化。但是,一个简单的构造函数注入不会对这两个类执行。这是因为每次调用add_new_thing时我都需要新的Thing_A和Thing_B实例,以便可以将Thing_A添加到array_of_thing_A。

如何使此功能单元可测试?更具体地说,我在PHPUnit中使用Thing_A和Thing_B的模拟来测试这个函数?

任何有代码示例的建议都将受到赞赏。

此外,我想提一下,Thing_A和Thing_B在我正在使用的代码库中的其他地方使用,使用这些类的代码最终需要进行单元测试。在我的情况下,过于本地化并且会在其他地方引起重复代码的解决方案不太理想。谢谢。

2 个答案:

答案 0 :(得分:1)

正如xmike提到的评论者所说,你可以使用factory pattern。您也可以通过ctor注入工厂对象。然后,您可以拥有一个工厂,提供Thing_AThing_B

的简化实例
class ThingFactory {
    public function buildThingA() {
        return new Thing_A(); // or MockThing_A if you go the ducktyping route
    }

    public function buildThingB() {
        return new Thing_B();
    }
}

class model_to_be_tested {
        // an array that holds a collection of thing A
        public $array_of_thing_A;

        // you could go the typed route and have an interface for this
        private $factory;

        // already doing constructor injection for the data object
        public __construct($data_object, $factory) {
         // details here
         $this->factory = $factory;
        }

        public function add_new_thing_A($has_relationship) {
          $thing_A = $this->factory->buildThingA();
          $thing_A->is_thing = true;
          $thing_A->has_relationship_with_thing_B = $has_relationship;

          if ($has_relationship) {
             $thing_B = $this->factory->buildThingB();
             $thing_A->relationship_with = $thing_B;
          }

          $this->array_of_thing_A[] = $thing_A;
      }
    }

答案 1 :(得分:0)

PHP是一种奇怪的语言,你不能将一个类赋给变量。但你可以把它作为一个字符串。在构造函数上将ThingA和ThingB作为字符串注入。你可以在字符串成员上调用new。

class ThingA {};
class ThingB{};

class model_to_be_tested {
    // an array that holds a collection of thing A
    public $array_of_thing_A;
    private $_thingA;
    private $_thingB;


    public function __construct($data_object, $thingA, $thingB) {
     $this->_thingA = $thingA;
     $this->_thingB = $thingB;
    }

    public function add_new_thing_A($has_relationship) {
       $thing_A = new $this->_thingA();

      if ($has_relationship) {
         $thing_B = new $this->_thingB();
      }

      $this->array_of_thing_A[] = $thing_A; 
  }
}


$model = new model_to_be_tested('foo', 'ThingA', 'ThingB');
$model->add_new_thing_A(true);

这里有一个实时版本:https://repl.it/@rmoskal/InconsequentialAnotherGermanshorthairedpointer

或者为类提供静态构造函数。