Testing

Getting rid of the slow Masstransit test harness

I wrote a blog about replacing the timeout based test harness with a semaphore driven one here. This made things much more robust when you want blackbox type testing, fire a number of events and wait until all have been digested and their spawned child events are digested.

This worked well and robust. But it still used the Masstransit harness for hosting. This made the InMemory bus more than twice as slow as hosting Masstransit in a service, including database I/O so probably a lot slower when only looking at bus performance.

But it’s pretty easy hosting Masstransit from a none service project like a test project. Instead of configuring with AddMassTransitTestHarness use the standard AddMasstransit extension method. Now events will not be consumed when you publish them, this is because the IHostedService haven’t been started. So that’s an easy fix. If we base the code on the IHarness from my previous blog post.

public Harness(IEnumerable<IHostedService> services)
{
    _services = services;
}

public async Task Start()
{
    var source = new CancellationTokenSource();

    foreach (var service in _services)
        await service.StartAsync(source.Token);
}

public async Task Stop()
{
    var source = new CancellationTokenSource();

    foreach (var service in _services)
        await service.StopAsync(source.Token);
}

Call Start from your test setup and stop from your test teardown. This will start the background workers for Masstransit and make sure it listens and consumes events. The service will not work unless you add logging to your IoC config.

new ServiceCollection()
    .AddLogging();

Coupled with the harness-code from previous blog post you now have a very robust and fast test harness. Full code below

(more…)

A better Masstransit Test harness

At my latest customer project I choose to use Masstransit for events and Sagas. Its been a bumpy ride with outboxes and such, but now we have a pretty stable foundation to build upon. One problem have been testing. I like black box testing of our domain. Something like this.


[TestClass]
public class When_doing_a_complete_booking : BusinessTest
{
    private Booking _result;
    private DateTime _date;
 
    [TestInitialize]
    public void Context()
    {
        Guid bookingKey = Guid.Empty;
        _date = DateTime.Now.AddDays(5);
 
        _result = Given(db => /* Setup here */)
            .When(() => new SearchQuery{ Date = _date, ...})
            .And(result =>
            {
                bookingKey = result.First().BookingKey;
                return new ReserveCommand { BookingKey = bookingKey, ... };
            })
            .And(() => new ConfirmCommand
            {
                BookingKey = bookingKey, 
                ...
            })
            .Then(db => db.Set<booking>().FirstOrDefaultAsync(b => b.BookingKey == bookingKey));
    }
 
    [TestMethod]
    public void It_should_book_correctly ()
    {
        Assert.IsNotNull(_result);
        Assert.IsTrue(...);
    }
}

Masstransit harness really doesn’t support black box type testing. Chris Patterson favors a more unit testing-oriented approach, were you fire events and your Tests assert that events were consumed. You can await consumption with the built in harness, but its timeout oriented which makes it slow and unstable.

(more…)

Mock and callback a generic method with unavailable type using Moq

This is as much a note to self as a blog post. I needed to test a method that was dependent on a API with a callback action where T was scoped internal in the library that I was testing. Rather than making the type public I went ahead and tried to mock it anyway 😀

The code that we want to test is called from third party API like

await hubProxyFactory
            .Create(hubUrl, configureConnection, async p =>
                {
                    proxy = p;
                    await SendQueuedSubscriptions();
                    p.On<Message>("onEvent", OnEvent);
                },
                Reconnected, FaultedConnection, ConnectionComplete);

Message is a private type and OnEvent is of type Action<Message>. Its the OnEvent method we want to test. So we need to mock On<T> without knowing T and we need to save a reference to the OnEvent even though T is unknown. It looks like this

                    mock.Setup(x => x.On("onEvent", It.IsAny<Action<It.IsAnyType>>())).Callback(
                        (string e, MulticastDelegate callback) =>
                        {
                            onEvent = callback;
                        });
(more…)

Flexible integration tests with dacpac support

Integration tests are an important aspect of software development, high code coverage does improve code quality. But the tests need to be flexible and fast so they do not hinder the developers in their daily work. On the build server speed doesn’t matter that much, but a good test suite must be fast enough so that the developers choose to use it instead of running the system manually to test their features. Thats how you get good code coverage. Sadly publishing a dacpac is anything but fast. But there are clever tactics you can apply to make it work good as your daily testing platform.
(more…)