繁体   English   中英

SUT父级使用get_class检查依赖项

[英]SUT parent checks dependencies with get_class

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

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);
  }
}

好的,很好,现在我只在一个位置进行检查,而不必担心在函数开始时执行空检查。 我现在所要解决的问题是我的Interactor正在对照静态类名请求数组检查类名。 因此,当我在测试过程中对模拟实体进行DI时,我的父Interactor会抛出一个异常,指出它不在预先批准的列表中。

下面是简化的Chess示例,以进行演示:

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数组中,因此注定会引发异常。

到目前为止,我想出的解决方法是包括在Entity中:

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

然后在Interactor->setEntity($entity)而不是使用get_class($entity)我将使用$entity->getClassName() ,这对于模拟来说很简单。

我认为我创建Interactor的方式与前面提到的内容是一致的,只采用了构造函数中的实体。 但是,当我注入模拟实体时,一切都感到与众不同。

1)有没有办法避免我的实体中出现getClassName()

2)我可以模拟的实体中是否有某些东西可以代替而在get_class()调用?

谢谢您的帮助!

您正在检查类的名称是否是$request数组中的键之一。 事实并非如此。 数组中的键是数字0、1、2,因此会引发异常。 我认为您想使用in_array代替。

尽管与此同时,该模拟仍然不会通过,因为您正在检查类名是否在$request 因此,该名称也将根本不存在,并且仍然会引发异常。

如果您的Interactor类所做的全部工作是确保将正确的对象传递到构造函数中,为什么不只使用PHP的本机类型提示呢?

您的Chess班级变为:

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

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

您无需完全使用getClassName()即可进行所需的类型检查。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM