MassTransit is an open source library that is an abstraction over some of the popular messaging/bus technologies. I have used it for interacting with RabbitMQ bus and have found the experience very pleasant.

There is a pitfall that most developers fall into (myself including) when writing a test for MassTransit consumer. In the below example test, asserting for message not to be published will only return to the caller after the default timeout of 6 seconds has passed.

[Fact]
public void Message_not_published()
{
    sut.Login(lockedOutUser);
    testHarness.Published.Select<IUserLoggedIn>()
      .Should().BeEmpty();
}

General advice 🫡 is to not write tests that asserts something didn’t happen. Rethink how you can rewrite the test when you reach for this.

If absolutely necessary, you can pass in an optional CancellationToken to the Select method that times out after a set period.

[Fact]
public void Message_not_published()
{
    sut.Login(lockedOutUser);
    using CancellationTokenSource cts = new ();
    cts.CancelAfter(100);
    testHarness.Published.Select<IUserLoggedIn>(cts.Token)
      .Should().BeEmpty();
}

You can override the default timeout value by setting TestInactivityTimeout property on the TestHarness.

/// <summary>
/// Timeout specifying the elapsed time with no bus activity after which the
/// test could be completed
/// </summary>
public TimeSpan TestInactivityTimeout { get; set; }

Another permutation of the above assertion is counting the number of messages published. This will also wait till the timeout period. However, Count doesn’t have an overload that takes in a CancellationToken.

testHarness.Published.Count().Should().Be(2);