单元测试/如何断言非模拟方法称为/ C#/ Rhino Mocks / NUnit

时间:2010-08-26 08:13:45

标签: c# unit-testing rhino-mocks

我有一个MailService,允许我发送实现以下界面的电子邮件。

public interface IMailService
  {
    bool SendRegisteringEmail(RegisterModel registerModel);
    bool SendMail(MailMessage mailMessage);
    MailMessage CreateRegisteringMailMessage(RegisterModel registerModel);

    IAppSettingsRepository AppSettingsRepository { get; set; }

    ISmtpClient SmtpClient { get; set; }
  }

函数SendRegisteringEmail应该调用CreateRegisteringMailMessage,然后将SendMessage返回给SendMail函数,SendRegisteringEmail应该返回SendMail的返回布尔值。

我正在使用NUnit和Rhino Mocks进行测试,我是新手测试(1周),我正在练习TDD(至少我尝试过)。我的问题是我不知道如何在调用SendRegisteringEmail时断言CreateRegisteringMailMessage被调用,因为MailService不是Mocked对象。 这是我的测试:

[Test]
public void SendRegisteringEmail_ShouldCallCreateRegisteringMailMessage()
{
  //Arrange
  //MailMessage mailMessage = new MailMessage();
  IMailService mailService = new MailService { AppSettingsRepository = CreateAppSettingsMockReposotory() };
  //ISmtpClient smtpClientStub = MockRepository.GenerateStub<ISmtpClient>();
  //mailService.SmtpClient = smtpClientStub;
  //smtpClientStub.Stub(f => f.Send(mailMessage)).Return(true);


  //Act
  mailService.SendRegisteringEmail(ValidRegisterModel);

  //Assert
  mailService.AssertWasCalled(f => f.CreateRegisteringMailMessage(ValidRegisterModel));
}

启动测试时出现以下错误: FtpWeb.Tests.MailServiceTests.SendRegisteringEmail_ShouldCallCreateRegisteringMailMessage: System.InvalidOperationException:对象'FtpWeb.Models.MailService'不是模拟对象。

我理解为什么我会收到此错误但现在如何测试我的通话。 因为它是同一个对象我不能嘲笑它来测试它。 如果有人能帮我解决这个问题。

感谢。

3 个答案:

答案 0 :(得分:3)

我不确定应该测试是否CreateRegisteringMailMessage被调用。您应该只是检查调用SendRegisteringEmail结果。您的MailService实施应该怎么做?据推测它会对另一项服务产生一些影响 - 所以测试一下。

这将是一个奇怪的接口设计,坚持调用一个方法将需要调用接口中的另一个方法 - 通常你可能会让两个方法调用一个私有的,常见的方法,例如。

答案 1 :(得分:1)

方法CreateRegisteringMailMessageSendMail似乎在比SendRegisteringEmail更低的抽象级别上。你可以考虑创建一个包含SendRegisteringEmail的更高级别的类,这个类将使用IMailService,你可以照常模拟和断言。

如果第一个解决方案不是一个选项,那么您应该将SendRegisteringEmail视为一个整体,因此您必须在单个方面测试CreateRegisteringMailMessageSendMail的副作用测试(有点代码味道,因此我建议提取另一层次的间接) - 见Jon的回答。

答案 2 :(得分:0)

这通常被称为被测试类中的“感知”:您必须找到一种方法来判断方法是否已被调用。每个人都应该拥有的“Working Effectively with Legacy Code”一书中详细介绍了这些事情(免责声明:我与该书的作者没有任何关系,我认为这本书很好)。

CreateRegisteringMailMessage方法有什么作用?它是否会影响呼叫期间传入的RegisterModel实例的内容?