【问题标题】:Spec-ing a class that instantiate something指定一个实例化某些东西的类
【发布时间】:2016-09-10 10:54:29
【问题描述】:

假设我有我指定的这个类(遵循 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 以创建新的LoggedMessage

问题二:如果不需要注入新的协作者,我如何确保我的规范每次都能正常工作,并且不会由于日期时间差异而随机失败?

【问题讨论】:

    标签: php bdd phpspec prophecy


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

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

      $em->persist(Argument::type(LoggedMessage::class))->shouldBeCalled(1);

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

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

    【讨论】:

    • 感谢您的回答。你所有的考虑都和我的一样,所以我想工厂是唯一的办法。然而第二点不是一个好点:对于这种例子来说太紧了(phpspec example to be clear)
    猜你喜欢
    • 2019-05-20
    • 2017-03-29
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 2020-12-14
    • 1970-01-01
    • 2013-08-28
    • 2021-06-18
    相关资源
    最近更新 更多