指定一个实例化某个东西的类

时间:2016-09-10 10:54:30

标签: php bdd phpspec prophecy

我们说我有这个课程,我正在指定(遵循BDD方法)

class Logger
{
    private $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function logMessageAsRead(Message $message)
    {
        $log = new LoggedMessage($message);
        $this->em->persist($message);
    }
}

LoggedMessage定义如下

class LoggedMessage
{
    private $date;

    private $message;

    public function __construct(Message $message)
    {
        $this->date = new \DateTime();
        $this->message = $message;
    }
}

有时我的规范示例由于在规范中实例化的Message日期与Logger类中的日期不一致而失败。

class LoggerSpec
{
    public function it_logs_a_message(Message $message, EntityManager $em)
    {
        $log = new LoggedMessage($message);
        $em->persist($log)->shouldBeCalled(1);

        $this->logMessageAsRead($message);
    }
}

问题一:我的代码中是否有气味,所以我需要创建一个协作者(即:工厂)并将其注入Logger以创建新的{{1} }?

问题二:如果没有必要注入新的合作者,我怎样才能确保我的规范每次都能正常工作而不会因日期时间差异而以随机方式失败?

1 个答案:

答案 0 :(得分:0)

  1. 注入LoggedMessage s的工厂将是一个很好的解决方案,特别是如果您不想关闭LoggedMessage的构造函数以防止修改。一般来说,将创建对象的关注与使用它分开是件好事。

  2. 最简单的解决方案是检查特定类型而不是具体实例:

    $ EM->坚持(参数::类型(LoggedMessage ::类)) - > shouldBeCalled(1);

  3. 如果您希望您的期望更具体,可以使用Argument::whichArgument::that

    $em->persist(Argument::which('getMessage', $message))->shouldBeCalled(1);
    $em->persist(Argument::that(function($arg) {
        return $arg->getDate() instanceof \DateTime;
    }))->shouldBeCalled(1);