Я тестирую объект, который предназначен для проверки того, владеет ли пользователь данным письмом. Поэтому при вызове метода «tryEmail» он отправляет сообщение с ссылкой для подтверждения на указанный адрес электронной почты. Мой тест выглядит так:
public function testSendingWasSuccessful() {
$confirmationObject = $this->getMock('LT\EmailConfirmation\Model\ConfirmationObjectInterface');
$testType = 'test.type';
$testEmail = '[email protected]';
$testData = [];
// EmailTester should create a new confirmation object.
$this->manager->expects(static::once())
->method('create')->with($testType, $testEmail)
->willReturn($confirmationObject);
// Then it should send the confirmation message.
$this->mailer->expects(static::once())
->method('send')->with(static::identicalTo($confirmationObject))
->willReturn(true);
// And save the confirmation object.
$this->manager->expects(static::once())
->method('save')->with(static::identicalTo($confirmationObject));
$tester = new EmailTester($this->repository, $this->manager, $this->confirmationHandler, $this->mailer);
static::assertTrue($tester->tryEmail($testType, $testEmail, $testData));
}
Теперь вы можете увидеть, что с ним не так — оно содержит несколько утверждений. Почему я решил использовать эти утверждения внутри одного теста? Потому что они зависят друг от друга. Таким образом, сообщение подтверждения следует отправлять только в том случае, если создан новый объект подтверждения, а объект подтверждения следует сохранять только в том случае, если сообщение подтверждения было отправлено, и в конце выводится вывод метода «tryEmail», использующего эти проверенные методы. утверждал.
Однако я чувствую, что случайно описал реализацию метода tryEmail с моими утверждениями. Но, похоже, это необходимо для полного охвата этого метода, и я должен быть уверен, что он всегда работает так, как должен. Я могу представить, как будут проходить ошибки, если я уберу любое из этих утверждений. Например: static::identicalTo($confirmationObject)
что в основном: check if the object passed to the mailer is the same as the one created before
, Если бы я изменил интерфейс почтовой программы, мне пришлось бы изменить и этот тест EmailTester
так что, похоже, я здесь что-то не так делаю. В то же время, однако — как я могу проверить приведенное выше утверждение, не вводя эту связь? Или, может быть, я должен просто оставить это непроверенным?
Я делаю это правильно или неправильно? Как я могу улучшить это? Когда действительно использовать утверждения на макетах?
Добавлено: Я только что подумал — не правда ли, что тестовый класс должен тестировать реализация (если реализация соответствует интерфейсу)? Это будет означать, что описание реализации в тесте на самом деле хорошая вещь, потому что оно гарантирует, что реализация работает правильно. Это также будет означать, что уровень привязки реализации будет перенесен на тест, и это неизбежно. Я здесь не прав?
Правило «одно утверждение на тест» состоит в том, чтобы ваши тесты были сосредоточены на одном конкретном поведении тестируемого кода. Наличие нескольких утверждений в тесте — это не плохо.
При использовании фиктивного объекта я предпочитаю иметь какие-то утверждения о заменяемых методах. Таким образом я гарантирую, что система будет использовать зависимости, как и ожидалось.
Вы тестируете класс, чтобы подтвердить поведение вашего кода. Утверждения, которые у вас есть, будут любыми проверками, которые вы сделаете вручную, чтобы убедиться, что класс ведет себя так, как вы ожидали. Поскольку вы ожидаете, что определенные методы будут вызываться определенным образом, вы хотите иметь утверждение для них.
Проблемы, которые я вижу с тестом, состоят в том, что у вас есть фиктивный объект, возвращающий фиктивный объект. Обычно это запах кода, который означает, что вы не передаете правильные зависимости. Вы могли бы переместить создание вашего LT\EmailConfirmation\Model\ConfirmationObjectInterface
возьмите объект из метода и передайте его как зависимость вашего метода. Замена первых двух параметров вашего метода на этот объект.
Похоже, что в этом тесте вы вообще не используете третий параметр, поэтому он не нужен.
Других решений пока нет …