# Testing NServiceBus Message Handlers

> A brief introduction to unit testing NServiceBus message handlers using the NServiceBus.Testing package

- URL: https://blog.nimblepros.com/blogs/testing-nservicebus-message-handlers/
- Author: [Kyle McMaster](https://blog.nimblepros.com/authors/kyle/)
- Published: 2024-04-15
- Series: [NServiceBus](https://blog.nimblepros.com/series/nservicebus/)
- Categories: [Software Development](https://blog.nimblepros.com/categories/software-development/)
- Publisher: [NimblePros](https://blog.nimblepros.com/)

---

This post is the fourth in a series on [NServiceBus](https://go.particular.net/using-nservicebus-2024), a popular messaging framework for building distributed systems. If you've missed any of the previous articles, be sure to [check out the series page](https://blog.nimblepros.com/series/nservicebus/) for all the related posts. In the [previous post](/blogs/commands-events-messages-explained/), we covered the different types of messages and how to utilize them in your NServiceBus applications. In this post, we'll take a step away from messaging-related features and focus on another important topic, Unit Testing! We'll look at how to write unit tests for NServiceBus message handlers using some of the utilities from the [NServiceBus.Testing version](https://www.nuget.org/packages/NServiceBus.Testing) package at version `8.1.0` at the time of writing.

## Verifying Side Effects with Unit Tests 🔬

Automated testing is a foundational practice for us at NimblePros. As a firm believer and practitioner of automated testing, I believe unit testing is a crucial part of the software development process. It allows developers to verify that their code behaves as expected under different conditions and prevent regressions. When it comes to NServiceBus classes that implement the `IHandleMessages<T>` interface known as message handlers, unit tests can help ensure that the handlers are processing messages correctly and producing any expected side effects. In this article, our focus will be on verifying that an instance of the `IMessageHandlerContext` is called whenever we expect to send a message or publish an event. We can even verify that the message being sent or published is the one we expect and has the correct data. We'll use the following message handler from the previous post as an example:

```csharp
public class ContributorCreateCommandHandler(IRepository<Contributor> _repository) 
  : IHandleMessages<ContributorCreateCommand>
{
  public async Task Handle(ContributorCreateCommand message, IMessageHandlerContext context)
  {
    var phoneNumber = new PhoneNumber(string.Empty, message.PhoneNumber, string.Empty);
    var contributor = new Contributor(message.Name, phoneNumber, ContributorStatus.NotSet);
    await _repository.AddAsync(contributor, context.CancellationToken);

    await context.Publish(new ContributorCreatedEvent
    {
      ContributorId = contributor.Id,
      Name = contributor.Name,
      Status = contributor.Status.ToString()
    });
  }
}
```

## Writing Unit Tests for IMessageHandlers ✅

To write unit tests for NServiceBus message handlers, we can use the `NServiceBus.Testing` package. This package provides utilities for testing message handlers in isolation, without the need to set up an entire NServiceBus endpoint. The package includes a `TestableMessageHandlerContext` class that simulates the behavior of an `IMessageHandlerContext` and allows us to verify the interactions between the message handler and the context. We'll skip any additional tests you may want to write like asserting that the repository receives a call to `AddAsync()` to focus on just the NServiceBus functionality now, but I recommend including those tests as well in your test suite. Here's a walkthrough of the process of writing a unit test for the `ContributorCreateCommandHandler`.

This test follows the [AAA style of unit testing](https://deviq.com/testing/arrange-act-assert). First, our test method sets up all the necessary objects and data. Then, we call the system under test (SUT) which is the `ContributorCreateCommandHandler` in this case, to act on its `Handle` method. Finally, we assert that the expected side effect occurred, which is that the `ContributorCreatedEvent` was published. The `TestableMessageHandlerContext` exposes properties such as `SentMessages` and `PublishedMessages` that we can use to verify that the message handler interacted with the context as expected. The following iteration of the test method verifies a single `ContributorCreatedEvent` is published. This code sample uses XUnit and NSubstitute. However, you can choose which testing frameworks and tools for your own. The key thing to notice is the `TestableMessageHandlerContext` that is provided by the `NServiceBus.Testing` package.

```csharp
[Fact]
public async Task ShouldPublishContributorCreatedEvent()
{
  var message = new ContributorCreateCommand
  {
    Name = "Test Contributor",
    PhoneNumber = "123-456-7890"
  };
  var phoneNumber = new PhoneNumber(string.Empty, message.PhoneNumber, string.Empty);
  var contributor = new Contributor(message.Name, phoneNumber, ContributorStatus.NotSet)
  {
    Id = 1
  };
  var repository = Substitute.For<IRepository<Contributor>>();
  repository
    .AddAsync(Arg.Any<Contributor>(), Arg.Any<CancellationToken>())
    .Returns(contributor);
  var context = new TestableMessageHandlerContext();
  var handler = new ContributorCreateCommandHandler(repository);

  await handler.Handle(message, context);

  context.PublishedMessages.Single().Message.Should().BeOfType<ContributorCreatedEvent>();
}
```

Depending on your confidence in your mapping code, you may also add assertions to verify the data in the published message. This requires a little more staging since we need to set up NSubstitute to return a contributor based on the message data but it's not too much more work. Notice how we're able to check the properties of the published message using the `As<T>()` extension method from the FluentAssertions library. Here's the updated test method that verifies the properties of the published `ContributorCreatedEvent`:

```csharp
[Fact]
public async Task ShouldPublishContributorCreatedEvent()
{
  var message = new ContributorCreateCommand
  {
    Name = "Test Contributor",
    PhoneNumber = "123-456-7890"
  };
  var phoneNumber = new PhoneNumber(string.Empty, message.PhoneNumber, string.Empty);
  var contributor = new Contributor(message.Name, phoneNumber, ContributorStatus.NotSet)
  {
    Id = 1
  };
  var repository = Substitute.For<IRepository<Contributor>>();
  repository
    .AddAsync(Arg.Any<Contributor>(), Arg.Any<CancellationToken>())
    .Returns(contributor);
  var context = new TestableMessageHandlerContext();
  var handler = new ContributorCreateCommandHandler(repository);

  await handler.Handle(message, context);

  using var assertionScope = new AssertionScope();
  var publishedMessage = context.PublishedMessages.Single();
  publishedMessage.Message.Should().BeOfType<ContributorCreatedEvent>();
  publishedMessage.Message.As<ContributorCreatedEvent>().ContributorId.Should().Be(1);
  publishedMessage.As<ContributorCreatedEvent>().Name.Should().Be(message.Name);
  publishedMessage.As<ContributorCreatedEvent>().Status.Should().Be(ContributorStatus.NotSet.Name);
}
```

## A quick note on the NServiceBus.Testing package 📝

As seen above, this package provides `TestableMessageHandlerContext` that enables us to write assertions based on its properties. Since the `IMessageSession` is also popular in NServiceBus applications, I thought I'd mention that the package also includes a `TestableMessageSession` as well as many more "testable" classes for faking other NServiceBus components. You can find more information on the [NServiceBus.Testing package](https://docs.particular.net/samples/unit-testing) in the official documentation.

## Wrapping up! 🎁

In this post, we've covered how to a write unit test for NServiceBus message handlers using the `NServiceBus.Testing` package. We've seen how to use the `TestableMessageHandlerContext` class to simulate the behavior of an `IMessageHandlerContext` and verify the interactions between the message handler and the context. By writing unit tests for message handlers, you can ensure that your NServiceBus endpoints are processing messages correctly and producing the expected side effects. Stay tuned for more content in this series, as we'll be exploring more advanced topics like Sagas and patterns like Unit of Work and Outbox in future posts.

## Resources 📚

- [Exploring Design Patterns for Testing Webinar](https://mailchi.mp/nimblepros/design-patterns-testing-recording)
- [NServiceBus](https://go.particular.net/using-nservicebus-2024)
- [NServiceBus Unit Testing](https://docs.particular.net/samples/unit-testing)
