Unit testing with NServiceBus
Developing enterprise-scale distributed systems is hard
and testing them is just as challenging a task.
The architectural approach supported by NServiceBus
makes these challenges more manageable. And the
testing facilities provided actually make
unit testing endpoints and workflows easy.
Developers can now develop their service layers
and long-running processes using test-driven development.
Unit testing the service layer
The service layer in an NServiceBus application is made out of message handlers.
Each class typically handles one specific type of message. Testing these classes is most often focused
on their externally visible behavior - the types of messages they send or reply with.
This is as simple to test as could be expected:
[Test]
public void TestHandler()
{
Test.Initialize();
Test.Handler<YourMessageHandler>()
.ExpectReply<YourResponseMessage>(m => m.String == "hello")
.OnMessage<YourRequestMessage>(m => m.String = "hello");
}
What this test is saying that when a message of the type YourRequestMessage is processed by
YourMessageHandler, it will respond with a message of the type YourResponseMessage. Also, if the
request message's String property value is "hello" than that will also be the value of the String
property of the response message.
Testing header manipulation
One of the responsibilities of the message handlers in the service layer is using data from headers
found in the request to make decisions, as well as setting headers on top of the response messages.
This is how this kind of functionality can be tested:
[Test]
public void TestHandler()
{
Test.Initialize();
Test.Handler<YourMessageHandler>()
.SetIncomingHeader("Test", "abc")
.ExpectReply<YourResponseMessage>(m => m.String == "hello")
.AssertOutgoingHeader("Test", "abc")
.OnMessage<YourRequestMessage>(m => m.String = "hello");
}
This test sets the value of the incoming header key "Test" to be the value "abc". The test also
asserts that the value of the outgoing header key "Test" will be "abc" as well.
Injecting additional dependencies into the service layer
Many of the message handling classes in the service layer will make use of other objects to perform
their work. When testing these classes, you'll want to replace those objects with "stubs" so that the
class under test is isolated. Here's how that's done:
[Test]
public void TestHandler()
{
Test.Initialize();
// initialize your mock-object library
var yourObj = // mock out the relevant interface
Test.Handler<YourMessageHandler>()
.WithExternalDependencies(h => h.Dependency = yourObj)
// rest of your test
}
One dependency that many message handlers will have is on the bus. That dependency will be filled
automatically by the testing infrastructure and does not need to be mocked out in your test.
Other service layer testing functionality
For every method on the bus there is a corresponding test method that sets up an expectation for that
call as shown below:
Next Steps
You may be interested in seeing:
How sagas work in NServiceBus
or go back to the documentation table of contents