應用程序使用我有NServiceBus在我的應用程序.NET應用程序的代碼:測試Bus.Send使用NServiceBus
Bus.Send<IServiceStarted>(e =>
{
e.ServiceInfo = ReadServiceInfo();
e.EventTime = DateProvider.Now;
});
你會如何單元測試這樣的代碼?
應用程序使用我有NServiceBus在我的應用程序.NET應用程序的代碼:測試Bus.Send使用NServiceBus
Bus.Send<IServiceStarted>(e =>
{
e.ServiceInfo = ReadServiceInfo();
e.EventTime = DateProvider.Now;
});
你會如何單元測試這樣的代碼?
只要你Bus
變量是IBus
例如,你可以簡單地提供一個嘲笑IBus
實現包含此方法的類,並驗證發送被稱爲它(與適當的代表,如果你願意的話)該方法被調用後進行測試。除此之外,你正在測試Bus.Send
本身,這不是你應該做的事情。
public class ClassThatSendsMessages
{
private readonly IBus _bus;
public ClassThatSendsMessages(IBus bus /*, ... */)
{
_bus = bus;
/* ... */
}
public void CodeThatSendsMessage()
{
/* ... */
_bus.Send<IMyMessage>(mm => mm.Property1 = "123");
/* ... */
}
}
public class ClassThatTestsClassThatSendsMessages
{
public void CallCodeThatSendsMessage()
{
//Mock IBus object here
var objectToTest = new ClassThatSendsMessages(mockedIBus /*, ... */)
objectToTest.CodeThatSendsMessage();
//Verify that IBus mock's Send() method was called
}
}
有接近測試委託的邏輯有兩種方法:你可以嘗試打破所提供的表達式樹,或者你可以把它改成一個命名的方法,並通過這種方式。我從來沒有得到深入的表達,所以我會提供後者的一個例子:
public static class MyMessageBuilder
{
public static void Build(IMyMessage message) { /* ... */ }
}
public class ClassThatTestsMyMessageBuilder
{
public void CallCodeThatBuildsMessage()
{
var message = Test.CreateInstance<IMyMessage>(MyMessageBuilder.Build);
//Verify message contents
}
}
用法:
public class ClassThatSendsMessages
{
private readonly IBus _bus;
public static Action<IMyMessage> BuildMessage { private get; set; }
public ClassThatSendsMessages(IBus bus /*, ... */)
{
_bus = bus;
/* ... */
}
public void CodeThatSendsMessage()
{
/* ... */
_bus.Send<IMyMessage>(mm => BuildMessage (mm));
/* ... */
}
}
我不知道一個容器,可以做委託注入的構造函數,但是我還沒有看起來很辛苦,所以這可能是更好的設置委託的方法。
編輯
正如我在我自己的測試,最近遇到這個問題,我真的不喜歡有拉法伸到自己的建設者。所以我開始發現我是否可以「在原地」測試代表。事實證明,您可以:
public class ClassThatTestsClassThatSendsMessages
{
public void CallCodeThatSendsMessage()
{
Action<IMyMessage> messageAction = null;
//Mock IBus object here
mockedIBus.Setup(b => b.Send(Args.IsAny<Action<IMyMessage>>()))
.Callback((Action<IMyMessage> a) => messageAction = a);
var myMessage = Test.CreateInstance<IMyMessage>();
var objectToTest = new ClassThatSendsMessages(mockedIBus /*, ... */)
//Run the code that sends the message
objectToTest.CodeThatSendsMessage();
//Run the code that populates the message
messageAction(myMessage);
//Verify expectations on Setups
//Verify the message contents;
}
}
這裏有權衡 - 拉消息建設者出到一個接口肯定比把它當作一個內嵌的委託更符合SRP(作爲測試清楚地表明:你必須行動兩次以測試所有代碼)。但是,它在代碼大小和可讀性方面都帶來了好處。
此外,這個代碼是Moq特定的;我不知道是否有可能從RhinoMocks模擬中獲得代表,或者語法會是什麼。
如果正在測試的代碼是消息處理程序,那麼您可以使用NServiceBus.Testing庫來爲您模擬總線,如果您使用setter注入了IBus屬性,它也會將它注入到您的處理程序中。 – 2010-10-12 05:16:23
arootbeer,對我來說難的部分是如何驗證Send方法是否與相應的委託調用? Rhino Mocks提供了一個方法AssertWasCalled,它接受參數的約束,但是它有一個約束,允許您驗證方法是否使用適當的委託來調用? – mgamer 2010-10-12 06:34:55
您可以嘗試使用GetArgumentsForCallsMadeOn來提取委託並檢查其屬性:http://kashfarooq.wordpress.com/2009/01/10/rhino-mocks-and-getargumentsforcallsmadeon/ – PatrickSteele 2010-10-12 12:01:55
查看NSB自帶的測試框架,它使用下面的Rhino:http://nservicebus.com/UnitTesting.aspx。下載中有幾個樣本與NUnit一起使用。你也可以在MSTest下運行它。
你問的是測試'Bus.Send',還是發送消息的代碼? – arootbeer 2010-10-11 19:01:50
arootbeer,我正在詢問測試發送消息的代碼。我想要測試的確切代碼在上面的問題中給出。 – mgamer 2010-10-11 20:35:53
我添加了一個關於就地測試委託代碼的編輯,以防您感興趣。 – arootbeer 2010-10-18 15:14:06