PHPUnit中的模拟对象有什么意义?

时间:2013-12-24 11:54:38

标签: php unit-testing mocking phpunit

我正在开发一个实习应用,可以在视图方法中发送一些电子邮件。现在我正在重建这个应用程序TDD风格,但我在某个时候陷入困境。我在网上搜索了如何使用PHPUnit测试电子邮件,解决方案是,使用模拟对象。我阅读了一些关于它的文章和教程,并使用模拟对象构建了一个测试。

测试通过,但我不明白为什么要使用模拟对象,如果你已经知道结果。我的意思是,如果你已经知道结果,你没有看到真正的方法失败?那么这不是测试使用电子邮件功能的方法的方法,还是我只是做错了?可能是第二个哈哈。

提前致谢,

Sjors

2 个答案:

答案 0 :(得分:1)

当您进行单元测试时,您应该尝试独立于系统的其他部分测试被测试的方法(被测试的工作单元)。一旦您被迫跨越系统边界,您的单元测试就会成为集成测试。集成测试往往更脆弱,更难写,更难维护。通过将邮件组件与创建邮件的方法隔离开来,您不再需要依赖邮件系统是否在单元测试运行时启动并运行。您可以自由地测试被测方法中的逻辑,而不必依赖于具体的实现。

有两类模拟测试,交互测试和基于状态的测试。我建议在谷歌上查找两者之间的差异。

我很遗憾不熟悉php的语法,我只能向您展示一个使用C#语法在您的案例中测试的示例,但我相信您将能够遵循代码。

public interface Mailer
{
  void Send(string to, string from, string subject, string body)
}

上面的界面将匹配实际发送邮件的邮件组件的签名(它知道smtp等)。

public class MailSender
{
  private IMailer _mailer;
  public MailSender(IMailer mailer)
  {
    _mailer = mailer;
  }

  public void GenerateMail(string to, string cc, string from, string subject, string body)
  {
    if (IsValidEmailAddress(to) == false) throw new InvalidEmailAddressException("To"); 
    if (IsEmptySubject(from) == false) throw new EmptySubjectException();    
    _mailer.Send(to, from, subject, body);
  }

  private bool IsValidEmailAddress(string emailAddress)
  {
    // some code/regex to check that the email address is valid
  }

  private boold IsEmptySubject(string subject)
  {
    // code to check if the subject is empty
  }
}

现在我们在GenerateMail方法中有逻辑。您可以编写单元测试以检查是否获得无效电子邮件地址和空主题的例外,并且您还可以编写单元测试以确保如果您有有效的电子邮件地址且主题不为空,则调用send方法使用每个参数中的正确信息模拟邮件发件人。这种类型的单元测试会进行交互测试,因为模拟只是验证方法被调用了。

希望这个解释有所帮助。

答案 1 :(得分:0)

使用模拟对象的原因是隔离。如果您编写单元测试,则希望它们与其他系统或代码尽可能隔离。因此名称单位测试。使用模拟可以让您将测试与其他系统隔离(在您的情况下是电子邮件)。 Misko Hevery http://www.youtube.com/watch?v=acjvKJiOvXw有一个演讲,比我更好地解释了这个方面。