Awesome
<img src="/src/icon.png" height="30px"> Verify.NServiceBus
Adds Verify support to verify NServiceBus.
See Milestones for release notes.
NuGet package
https://nuget.org/packages/Verify.NServiceBus/
Usage
<!-- snippet: enable --><a id='snippet-enable'></a>
[ModuleInitializer]
public static void Initialize() =>
VerifyNServiceBus.Initialize();
<sup><a href='/src/Tests/ModuleInitializer.cs#L3-L9' title='Snippet source file'>snippet source</a> | <a href='#snippet-enable' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Verifying a context
Given the following handler:
<!-- snippet: SimpleHandler --><a id='snippet-SimpleHandler'></a>
public class MyHandler :
IHandleMessages<MyRequest>
{
public async Task Handle(MyRequest message, HandlerContext context)
{
await context.Publish(
new MyPublishMessage
{
Property = "Value"
});
await context.Reply(
new MyReplyMessage
{
Property = "Value"
});
var sendOptions = new SendOptions();
sendOptions.DelayDeliveryWith(TimeSpan.FromHours(12));
await context.Send(
new MySendMessage
{
Property = "Value"
},
sendOptions);
await context.ForwardCurrentMessageTo("newDestination");
}
}
<sup><a href='/src/Tests/Snippets/MyHandler.cs#L1-L33' title='Snippet source file'>snippet source</a> | <a href='#snippet-SimpleHandler' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->The test that verifies the resulting context:
<!-- snippet: HandlerTest --><a id='snippet-HandlerTest'></a>
[Fact]
public async Task VerifyHandlerResult()
{
var handler = new MyHandler();
var context = new RecordingHandlerContext();
var message = new MyRequest();
await handler.Handle(message, context);
await Verify(context);
}
<sup><a href='/src/Tests/Snippets/HandlerTests.cs#L3-L17' title='Snippet source file'>snippet source</a> | <a href='#snippet-HandlerTest' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->The resulting verification file is as follows:
<!-- snippet: HandlerTests.VerifyHandlerResult.verified.txt --><a id='snippet-HandlerTests.VerifyHandlerResult.verified.txt'></a>
{
Forward: [
newDestination
],
Publish: [
{
MyPublishMessage: {
Property: Value
}
}
],
Reply: [
{
MyReplyMessage: {
Property: Value
}
}
],
Send: [
{
MySendMessage: {
Property: Value
},
Options: {
DeliveryDelay: 12:00:00
}
}
]
}
<sup><a href='/src/Tests/Snippets/HandlerTests.VerifyHandlerResult.verified.txt#L1-L29' title='Snippet source file'>snippet source</a> | <a href='#snippet-HandlerTests.VerifyHandlerResult.verified.txt' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Recording
Recording allows all message interaction with the test context to be captured and then verified.
<!-- snippet: RecordingHandlerTests --><a id='snippet-RecordingHandlerTests'></a>
[Fact]
public async Task VerifyHandlerResult()
{
Recording.Start();
var handler = new MyHandler();
var context = new RecordingHandlerContext();
var message = new MyRequest();
await handler.Handle(message, context);
await Verify("some other data");
}
<sup><a href='/src/Tests/Snippets/RecordingHandlerTests.cs#L3-L18' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingHandlerTests' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->The resulting context verification file is as follows:
<!-- snippet: RecordingHandlerTests.VerifyHandlerResult.verified.txt --><a id='snippet-RecordingHandlerTests.VerifyHandlerResult.verified.txt'></a>
{
target: some other data,
message: [
{
Publish: {
MyPublishMessage: {
Property: Value
}
}
},
{
Reply: {
MyReplyMessage: {
Property: Value
}
}
},
{
Send: {
MySendMessage: {
Property: Value
},
Options: {
DeliveryDelay: 12:00:00
}
}
}
]
}
<sup><a href='/src/Tests/Snippets/RecordingHandlerTests.VerifyHandlerResult.verified.txt#L1-L29' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingHandlerTests.VerifyHandlerResult.verified.txt' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Verifying a Saga
Given the following handler:
<!-- snippet: SimpleSaga --><a id='snippet-SimpleSaga'></a>
public class MySaga :
Saga<MySaga.MySagaData>,
IHandleMessages<MyRequest>
{
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<MySagaData> mapper) =>
mapper.ConfigureMapping<MyRequest>(message => message.OrderId)
.ToSaga(sagaData => sagaData.OrderId);
public async Task Handle(MyRequest message, HandlerContext context)
{
await context.Publish(
new MyPublishMessage
{
Property = "Value"
});
Data.MessageCount++;
}
public class MySagaData :
ContainSagaData
{
public Guid OrderId { get; set; }
public int MessageCount { get; set; }
}
}
<sup><a href='/src/Tests/Snippets/MySaga.cs#L1-L30' title='Snippet source file'>snippet source</a> | <a href='#snippet-SimpleSaga' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->The test that verifies the resulting context:
<!-- snippet: SagaTest --><a id='snippet-SagaTest'></a>
[Fact]
public async Task VerifySagaResult()
{
var saga = new MySaga
{
Data = new()
};
var context = new RecordingHandlerContext();
var message = new MyRequest();
await saga.Handle(message, context);
await Verify(new
{
context,
saga
});
}
<sup><a href='/src/Tests/Snippets/SagaTests.cs#L3-L25' title='Snippet source file'>snippet source</a> | <a href='#snippet-SagaTest' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->The resulting verification file is as follows:
<!-- snippet: SagaTests.VerifySagaResult.verified.txt --><a id='snippet-SagaTests.VerifySagaResult.verified.txt'></a>
{
context: {
Publish: [
{
MyPublishMessage: {
Property: Value
}
}
]
},
saga: {
MessageCount: 1
}
}
<sup><a href='/src/Tests/Snippets/SagaTests.VerifySagaResult.verified.txt#L1-L14' title='Snippet source file'>snippet source</a> | <a href='#snippet-SagaTests.VerifySagaResult.verified.txt' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Example behavior change
The next time there is a code change, that results in a different resulting interactions with NServiceBus, those changes can be visualized. For example if the DelayDeliveryWith
is changed from 12 hours to 1 day:
<a id='snippet-SimpleHandlerV2'></a>
await context.Publish(
new MyPublishMessage
{
Property = "Value"
});
await context.Reply(
new MyReplyMessage
{
Property = "Value"
});
var sendOptions = new SendOptions();
sendOptions.DelayDeliveryWith(TimeSpan.FromDays(1));
await context.Send(
new MySendMessage
{
Property = "Value"
},
sendOptions);
await context.ForwardCurrentMessageTo("newDestination");
<sup><a href='/src/Tests/Snippets/MyHandlerV2.cs#L6-L31' title='Snippet source file'>snippet source</a> | <a href='#snippet-SimpleHandlerV2' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Then the resulting visualization diff would look as follows:
Message to Handler mapping
MessageToHandlerMap
allows verification of message that do not have a handler.
For example:
<!-- snippet: MessageToHandlerMap --><a id='snippet-MessageToHandlerMap'></a>
var map = new MessageToHandlerMap();
map.AddMessagesFromAssembly<MyMessage>();
map.AddHandlersFromAssembly<MyHandler>();
await Verify(map);
<sup><a href='/src/Tests/MessageToHandlerMapTests.cs#L6-L11' title='Snippet source file'>snippet source</a> | <a href='#snippet-MessageToHandlerMap' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Would result in:
<!-- snippet: MessageToHandlerMapTests.Integration.verified.txt --><a id='snippet-MessageToHandlerMapTests.Integration.verified.txt'></a>
{
MessagesWithNoHandler: [
MessageToHandlerMapTests.MessageWithNoHandler
]
}
<sup><a href='/src/Tests/MessageToHandlerMapTests.Integration.verified.txt#L1-L5' title='Snippet source file'>snippet source</a> | <a href='#snippet-MessageToHandlerMapTests.Integration.verified.txt' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Icon
Approval designed by Mike Zuidgeest from The Noun Project.