我正在测试一个对象,该对象旨在测试用户是否拥有给定的电子邮件。因此,在调用“tryEmail”方法时,它会向给定的电子邮件地址发送带有确认链接的消息。我的测试如下所示:PHPUnit:在一个测试中对模拟方法使用多个断言是否是一种不好的做法?
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'的评论给了我一些想法。我有意识地设计它,以尽量减少使用此对象时所需的工作量。现在我几乎可以在控制器中使用一个函数'tryEmail'并完成。否则,我将不得不拉动管理器,并在控制器中创建确认对象,然后通过'tryEmail'方法传递它,这将只是我的Controller中的更多代码,这似乎是一个坏主意。你确定这会有所改进吗? –
我很有信心。我为你的对象增加了灵活性,'EmailTester'现在可以采用不同类型的对象。它也让他们专注。如果您需要发送不同的电子邮件类型,则此对象应该能够毫无问题地处理它。 – Schleis