{"id":18937453,"url":"https://github.com/verifytests/verify.nservicebus","last_synced_at":"2025-04-15T18:32:05.161Z","repository":{"id":37287630,"uuid":"223719540","full_name":"VerifyTests/Verify.NServiceBus","owner":"VerifyTests","description":"Adds Verify support to verify NServiceBus Test Contexts","archived":false,"fork":false,"pushed_at":"2025-04-10T21:37:01.000Z","size":1207,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-10T22:30:56.422Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/VerifyTests.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"VerifyTests"}},"created_at":"2019-11-24T09:21:49.000Z","updated_at":"2025-04-10T21:37:03.000Z","dependencies_parsed_at":"2024-01-10T03:24:56.577Z","dependency_job_id":"fa6a8791-355d-4113-8c7d-09f242f180f2","html_url":"https://github.com/VerifyTests/Verify.NServiceBus","commit_stats":{"total_commits":786,"total_committers":4,"mean_commits":196.5,"dds":0.5648854961832062,"last_synced_commit":"ae0b4e1e4c3539a443e24a57972183b8e1f505c1"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VerifyTests%2FVerify.NServiceBus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VerifyTests%2FVerify.NServiceBus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VerifyTests%2FVerify.NServiceBus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VerifyTests%2FVerify.NServiceBus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VerifyTests","download_url":"https://codeload.github.com/VerifyTests/Verify.NServiceBus/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249129234,"owners_count":21217311,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T12:11:14.186Z","updated_at":"2025-04-15T18:32:00.148Z","avatar_url":"https://github.com/VerifyTests.png","language":"C#","funding_links":["https://github.com/sponsors/VerifyTests"],"categories":[],"sub_categories":[],"readme":"# \u003cimg src=\"/src/icon.png\" height=\"30px\"\u003e Verify.NServiceBus\n\n[![Discussions](https://img.shields.io/badge/Verify-Discussions-yellow?svg=true\u0026label=)](https://github.com/orgs/VerifyTests/discussions)\n[![Build status](https://ci.appveyor.com/api/projects/status/haolkpausmys1ur4?svg=true)](https://ci.appveyor.com/project/SimonCropp/Verify-NServiceBus)\n[![NuGet Status](https://img.shields.io/nuget/v/Verify.NServiceBus.svg)](https://www.nuget.org/packages/Verify.NServiceBus/)\n\nAdds [Verify](https://github.com/VerifyTests/Verify) support to verify NServiceBus.\n\n**See [Milestones](../../milestones?state=closed) for release notes.**\n\n\n## NuGet package\n\nhttps://nuget.org/packages/Verify.NServiceBus/\n\n\n## Usage\n\n\u003c!-- snippet: enable --\u003e\n\u003ca id='snippet-enable'\u003e\u003c/a\u003e\n```cs\n[ModuleInitializer]\npublic static void Initialize() =\u003e\n    VerifyNServiceBus.Initialize();\n```\n\u003csup\u003e\u003ca href='/src/Tests/ModuleInitializer.cs#L3-L9' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-enable' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n\n### Verifying a context\n\nGiven the following handler:\n\n\u003c!-- snippet: SimpleHandler --\u003e\n\u003ca id='snippet-SimpleHandler'\u003e\u003c/a\u003e\n```cs\npublic class MyHandler :\n    IHandleMessages\u003cMyRequest\u003e\n{\n    public async Task Handle(MyRequest message, HandlerContext context)\n    {\n        await context.Publish(\n            new MyPublishMessage\n            {\n                Property = \"Value\"\n            });\n\n        await context.Reply(\n            new MyReplyMessage\n            {\n                Property = \"Value\"\n            });\n\n        var sendOptions = new SendOptions();\n        sendOptions.DelayDeliveryWith(TimeSpan.FromHours(12));\n        await context.Send(\n            new MySendMessage\n            {\n                Property = \"Value\"\n            },\n            sendOptions);\n\n        await context.ForwardCurrentMessageTo(\"newDestination\");\n    }\n}\n```\n\u003csup\u003e\u003ca href='/src/Tests/Snippets/MyHandler.cs#L1-L33' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-SimpleHandler' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nThe test that verifies the resulting context:\n\n\u003c!-- snippet: HandlerTest --\u003e\n\u003ca id='snippet-HandlerTest'\u003e\u003c/a\u003e\n```cs\n[Fact]\npublic async Task VerifyHandlerResult()\n{\n    var handler = new MyHandler();\n    var context = new RecordingHandlerContext();\n\n    var message = new MyRequest();\n    await handler.Handle(message, context);\n\n    await Verify(context);\n}\n```\n\u003csup\u003e\u003ca href='/src/Tests/Snippets/HandlerTests.cs#L3-L17' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-HandlerTest' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nThe resulting verification file is as follows:\n\n\u003c!-- snippet: HandlerTests.VerifyHandlerResult.verified.txt --\u003e\n\u003ca id='snippet-HandlerTests.VerifyHandlerResult.verified.txt'\u003e\u003c/a\u003e\n```txt\n{\n  Forward: [\n    newDestination\n  ],\n  Publish: [\n    {\n      MyPublishMessage: {\n        Property: Value\n      }\n    }\n  ],\n  Reply: [\n    {\n      MyReplyMessage: {\n        Property: Value\n      }\n    }\n  ],\n  Send: [\n    {\n      MySendMessage: {\n        Property: Value\n      },\n      Options: {\n        DeliveryDelay: 12:00:00\n      }\n    }\n  ]\n}\n```\n\u003csup\u003e\u003ca href='/src/Tests/Snippets/HandlerTests.VerifyHandlerResult.verified.txt#L1-L29' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-HandlerTests.VerifyHandlerResult.verified.txt' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n\n#### Recording\n\nRecording allows all message interaction with the test context to be captured and then verified.\n\n\u003c!-- snippet: RecordingHandlerTests --\u003e\n\u003ca id='snippet-RecordingHandlerTests'\u003e\u003c/a\u003e\n```cs\n[Fact]\npublic async Task VerifyHandlerResult()\n{\n    Recording.Start();\n    var handler = new MyHandler();\n    var context = new RecordingHandlerContext();\n\n    var message = new MyRequest();\n    await handler.Handle(message, context);\n\n    await Verify(\"some other data\");\n}\n```\n\u003csup\u003e\u003ca href='/src/Tests/Snippets/RecordingHandlerTests.cs#L3-L18' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-RecordingHandlerTests' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nThe resulting context verification file is as follows:\n\n\u003c!-- snippet: RecordingHandlerTests.VerifyHandlerResult.verified.txt --\u003e\n\u003ca id='snippet-RecordingHandlerTests.VerifyHandlerResult.verified.txt'\u003e\u003c/a\u003e\n```txt\n{\n  target: some other data,\n  message: [\n    {\n      Publish: {\n        MyPublishMessage: {\n          Property: Value\n        }\n      }\n    },\n    {\n      Reply: {\n        MyReplyMessage: {\n          Property: Value\n        }\n      }\n    },\n    {\n      Send: {\n        MySendMessage: {\n          Property: Value\n        },\n        Options: {\n          DeliveryDelay: 12:00:00\n        }\n      }\n    }\n  ]\n}\n```\n\u003csup\u003e\u003ca href='/src/Tests/Snippets/RecordingHandlerTests.VerifyHandlerResult.verified.txt#L1-L29' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-RecordingHandlerTests.VerifyHandlerResult.verified.txt' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n\n#### Verifying a Saga\n\nGiven the following handler:\n\n\u003c!-- snippet: SimpleSaga --\u003e\n\u003ca id='snippet-SimpleSaga'\u003e\u003c/a\u003e\n```cs\npublic class MySaga :\n    Saga\u003cMySaga.MySagaData\u003e,\n    IHandleMessages\u003cMyRequest\u003e\n{\n    protected override void ConfigureHowToFindSaga(SagaPropertyMapper\u003cMySagaData\u003e mapper) =\u003e\n        mapper.ConfigureMapping\u003cMyRequest\u003e(message =\u003e message.OrderId)\n            .ToSaga(sagaData =\u003e sagaData.OrderId);\n\n    public async Task Handle(MyRequest message, HandlerContext context)\n    {\n        await context.Publish(\n            new MyPublishMessage\n            {\n                Property = \"Value\"\n            });\n\n        Data.MessageCount++;\n    }\n\n    public class MySagaData :\n        ContainSagaData\n    {\n        public Guid OrderId { get; set; }\n        public int MessageCount { get; set; }\n    }\n}\n```\n\u003csup\u003e\u003ca href='/src/Tests/Snippets/MySaga.cs#L1-L30' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-SimpleSaga' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nThe test that verifies the resulting context:\n\n\u003c!-- snippet: SagaTest --\u003e\n\u003ca id='snippet-SagaTest'\u003e\u003c/a\u003e\n```cs\n[Fact]\npublic async Task VerifySagaResult()\n{\n    var saga = new MySaga\n    {\n        Data = new()\n    };\n\n    var context = new RecordingHandlerContext();\n\n    var message = new MyRequest();\n    await saga.Handle(message, context);\n\n    await Verify(new\n    {\n        context,\n        saga\n    });\n}\n```\n\u003csup\u003e\u003ca href='/src/Tests/Snippets/SagaTests.cs#L3-L25' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-SagaTest' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nThe resulting verification file is as follows:\n\n\u003c!-- snippet: SagaTests.VerifySagaResult.verified.txt --\u003e\n\u003ca id='snippet-SagaTests.VerifySagaResult.verified.txt'\u003e\u003c/a\u003e\n```txt\n{\n  context: {\n    Publish: [\n      {\n        MyPublishMessage: {\n          Property: Value\n        }\n      }\n    ]\n  },\n  saga: {\n    MessageCount: 1\n  }\n}\n```\n\u003csup\u003e\u003ca href='/src/Tests/Snippets/SagaTests.VerifySagaResult.verified.txt#L1-L14' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-SagaTests.VerifySagaResult.verified.txt' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n\n### Example behavior change\n\nThe 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:\n\n\u003c!-- snippet: SimpleHandlerV2 --\u003e\n\u003ca id='snippet-SimpleHandlerV2'\u003e\u003c/a\u003e\n```cs\nawait context.Publish(\n    new MyPublishMessage\n    {\n        Property = \"Value\"\n    });\n\nawait context.Reply(\n    new MyReplyMessage\n    {\n        Property = \"Value\"\n    });\n\nvar sendOptions = new SendOptions();\nsendOptions.DelayDeliveryWith(TimeSpan.FromDays(1));\nawait context.Send(\n    new MySendMessage\n    {\n        Property = \"Value\"\n    },\n    sendOptions);\n\nawait context.ForwardCurrentMessageTo(\"newDestination\");\n```\n\u003csup\u003e\u003ca href='/src/Tests/Snippets/MyHandlerV2.cs#L6-L31' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-SimpleHandlerV2' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nThen the resulting visualization diff would look as follows:\n\n![visualization diff](/src/approvaltests-diff.png)\n\n\n### Message to Handler mapping\n\n`MessageToHandlerMap` allows verification of message that do not have a handler.\n\nFor example:\n\n\u003c!-- snippet: MessageToHandlerMap --\u003e\n\u003ca id='snippet-MessageToHandlerMap'\u003e\u003c/a\u003e\n```cs\nvar map = new MessageToHandlerMap();\nmap.AddMessagesFromAssembly\u003cMyMessage\u003e();\nmap.AddHandlersFromAssembly\u003cMyHandler\u003e();\nawait Verify(map);\n```\n\u003csup\u003e\u003ca href='/src/Tests/MessageToHandlerMapTests.cs#L6-L11' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-MessageToHandlerMap' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nWould result in:\n\n\u003c!-- snippet: MessageToHandlerMapTests.Integration.verified.txt --\u003e\n\u003ca id='snippet-MessageToHandlerMapTests.Integration.verified.txt'\u003e\u003c/a\u003e\n```txt\n{\n  MessagesWithNoHandler: [\n    MessageToHandlerMapTests.MessageWithNoHandler\n  ]\n}\n```\n\u003csup\u003e\u003ca href='/src/Tests/MessageToHandlerMapTests.Integration.verified.txt#L1-L5' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-MessageToHandlerMapTests.Integration.verified.txt' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n\n## Icon\n\n[Approval](https://thenounproject.com/term/approval/1759519/) designed by [Mike Zuidgeest](https://thenounproject.com/zuidgeest/) from [The Noun Project](https://thenounproject.com/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fverifytests%2Fverify.nservicebus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fverifytests%2Fverify.nservicebus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fverifytests%2Fverify.nservicebus/lists"}