首页 > 解决方案 > SUT parent 使用 get_class 检查依赖项

问题描述

当我在各处执行空检查以确保我的交互器具有必要的实体时,它就开始了。幸运的是,我看到这篇文章指出不允许实体处于无效状态,请在您的构造函数中进行检查。现在我的交互protected static $request器用来明确说明他们需要哪些实体,然后在实例化期间传入。我选择了静态,因此可以在创建交互器实例之前完成检查。

abstract class Interactor {
  protected static $request = [];
  protected $entities = [];

  final public function __construct(Entity ...$entities) {
    $this->setEntities(...$entities);
    $this->checkEntities();
  }

  final private function setEntities(Entity ...$entities) {
    foreach($entities as $entity) {
      $this->setEntity($entity);
    }
  }
  final private function setEntity(Entity $entity){
    $className = get_class($entity);

    if (!in_array($className, static::$request)){
      throw new Exception("Not a requested entity");
    }
    $this->entities[$className] = $entity;
  }
  final private function checkEntities(){
    if (count(static::$request) != count($this->entities))
      throw new Exception("Entity mismatch");

    foreach(static::$request as $index=>$name) {
      if (!array_key_exists($name, $this->entities))
        throw new Exception("Missing requested entity ($name)");
      if (!is_a($this->entities[$name], $name))
        throw new Exception("Not the specified entity");
    }
  }

  final public static function getRequest(){
    return array_values(static::$request);
  }
}

好的,现在我只在一个位置进行检查,我不需要担心在我的函数开始时执行空检查。我现在的方式的问题是我的交互器正在根据静态类名请求数组检查类名。因此,当我在测试期间 DI 模拟实体时,我的父交互器会抛出一个异常,说它不在预先批准的列表中。

为了演示以下简化的国际象棋示例:

class Chess extends Interactor {
  protected static $request = ['Piece','Engine','Board'];
}

然后我们有我们的实体:

abstract class Entity {}
class Piece extends Entity {}
class Engine extends Entity {}
class Board extends Entity {}

最后是我们的测试:

class ChessTest extends TestCase {
  function setUp(){
    $this->piece = $this->getMockBuilder(Piece::class)->getMock();
    $this->engine = $this->getMockBuilder(Engine::class)->getMock();
    $this->board = $this->getMockBuilder(Board::class)->getMock();

    $this->chess = new Chess($this->piece, $this->engine, $this->board);
  }
  function testCanSetup(){
    $this->assertTrue(
      is_a($this->chess, Chess::class)
    );
  }
}

抛出异常:未请求交互器接收实体(Mock_Piece_faaf8b14)

当然 Mock_Piece_faaf8b14 不会出现在我们的static::$request数组中,所以这注定会抛出异常。

到目前为止我想出的解决方法是包含在实体中:

public function getClassName(){
  return get_called_class();
}

然后Interactor->setEntity($entity)代替使用,get_class($entity)我会使用$entity->getClassName()which 然后变得微不足道来模拟。

我认为我创建交互器的方式与前面提到的帖子的内容一致,只采用构造函数中的实体。然而,当我注入模拟实体时,这一切都感觉不同了。

1)有没有办法getClassName()在我的实体中避免?

2)我可以模拟的实体中是否有一些东西被调用get_class()

谢谢您的帮助!

标签: phpdependency-injectionphpunit

解决方案


您正在检查您的班级名称是否是$request数组中的键之一。事实并非如此。数组中的键是数字 0、1、2,所以你抛出了异常。我认为你想in_array改用。

尽管同时,这仍然不会通过模拟,因为您正在检查类名是否在$request. 所以名字也根本不存在,仍然会抛出异常。

如果你的Interactor类所做的只是确保将正确的对象传递给构造函数,为什么不直接使用 PHP 的本机类型提示呢?

你的Chess班级变成:

class Chess {
    public function __construct(Piece $piece, Engine $engine, Board $board) { }
}

PHP 将确保传入的对象是正确的类型,并允许您模拟它们以进行测试。

您无需使用即可获得所需的类型检查getClassName()


推荐阅读