Допустим, у меня есть этот класс, который я задавал (следуя 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
?
Вопрос номер два: если нет необходимости вводить нового соавтора, как я могу быть уверен, что моя спецификация работает каждый раз и не выходит из строя случайным образом из-за несоответствия даты и времени?
Инъекционная фабрика LoggedMessage
S было бы хорошим решением, особенно если вы не хотите закрывать конструктор LoggedMessage
против модификаций. В общем, хорошо отделить заботу о создании объекта от его использования.
Простейшим решением было бы проверить конкретный тип вместо конкретного экземпляра:
$ Em-> сохраняются (Аргумент :: тип (LoggedMessage :: класс)) -> shouldBeCalled (1);
Если вы хотите, чтобы ваши ожидания были более конкретными, вы можете использовать Argument::which
или же Argument::that
:
$em->persist(Argument::which('getMessage', $message))->shouldBeCalled(1);
$em->persist(Argument::that(function($arg) {
return $arg->getDate() instanceof \DateTime;
}))->shouldBeCalled(1);
Других решений пока нет …