2011-06-30 75 views
3

通常,当我需要嘲笑一个类进行测试时,我会使用一个库,如Rhino Mocks。在这里我有一个名为MyService的课程,预计需要IEmailSender模拟验证交互

public class MyService 
{ 
    private readonly IEmailSender sender; 

    public MyService(IEmailSender sender) 
    { 
     this.sender = sender; 
    } 

    public void Start() 
    { 
     this.sender.SendEmail(); 
    } 
} 

如果我需要测试这两个对象之间的互动,我的测试将是这个样子:

[TestMethod] 
public void Start_Test_Using_Rhino_Mocks() 
{ 
    IEmailSender emailSender = MockRepository.GenerateMock<IEmailSender>(); 

    MyService service = new MyService(emailSender); 
    service.Start(); 

    emailSender.AssertWasCalled 
     (
      x => x.SendEmail(), 
      c => c.Repeat.Once() 
     ); 
} 

在上述试验中,我使用犀牛制品产生的模拟和断言SendEmail()方法被调用一次。

但是如果我不能使用Rhino Mocks并且不得不创建手动模拟呢?

public class MockEmailSender : IEmailSender 
{ 
    public void SendEmail() 
    { 
    } 
} 

[TestMethod] 
public void Start_Test_Using_Manual_Mocks() 
{ 
    MockEmailSender emailSender = new MockEmailSender(); 

    MyService service = new MyService(emailSender); 
    service.Start(); 

    // How do I test the interaction? 
} 

与模拟,我手动创建的,我怎么会验证SendEmail()方法被调用?我可以把我的断言放在模拟的SendEmail()方法中,但是这会使测试很难理解,因为当我看着测试时我不会立即看到发生了什么。

回答

4

一个非常简单的解决办法有你手动模拟只是一个StateHolder的,与柜台办理调用每个方法。但它的脆弱......

public class MockEmailSender : IEmailSender 
{ 
    public int SendCount = 0; 

    public void SendMail(...) 
    { 
     SendCount++; 
    } 

    // ... other IEmailSender methods ... 
} 

然后,只需查询sendcount个让你的方法调用,并确保它的== 1

记住,犀牛嘲笑为你动态创建此之后 - 如果你手动执行,您必须在编译时间之前手动对接口更改作出反应。

1

我觉得你比从测试throgh MockEmailSender像“sendMailWasInvoked()”或类似这样的新方法设置标志“SendEmail()”,并检查该标志没有其他选择(这实际上是一种“验证”)。你可以扩展这个来计算调用次数,参数...

0

以及我会建议不要创建任何手动Mocks(因为如果你添加新的方法接口,它会被打破)。

如果你真的必须这样做,当在MockEmailSender中暴露一些counter/bool时,你可以稍后再声明它。

Assert.IsTrue(emailSender.IsCalled)