2011-06-30 76 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)