When unit testing, it is common to create a fake implementation of an interface so that you can test another component in isolation. But how do you handle the case where each test needs a fake that does something different?

Here’s an approach that I’ve found quite useful - a fake implementation that allows you to plug in the behaviour needed for the test at hand.

Consider a simple interface for sending messages:

public interface IMessageDispatcher<T>
{
    void SendMessage(T message);
    void PostMessage(T message);
}

Using explicit implementation of the interface, we can create a fake that makes it really easy for consumers to provide their own functionality:

public class FakeMessageDispatcher<T> : IMessageDispatcher<T>
{
    public Action<T> SendMessage { get; set; }
    public Action<T> PostMessage { get; set; }

    void IMessageDispatcher<T>.SendMessage(T message)
        => SendMessage?.Invoke(message);

    void IMessageDispatcher<T>.PostMessage(T message)
        => PostMessage?.Invoke(message);
}

This fake acts as a null implementation if not configured; the writable properties SendMessage and PostMessage allow consumers to provide their own implementation.

For example, here’s a simple test class demonstration.

public class MessengerTests
{
    private readonly FakeMessageDispatcher<string> _dispatcher;
    private readonly Store _store;

    public MessengerTests()
    {
        _dispatcher = new FakeMessageDispatcher<string>();
        _store = new Store(_dispatcher);
    }

    [Fact]
    public void Purchase_GivenProduct_SendsMessage()
    {
        string message = null;
        _dispatcher.SendMessage = m => message = m;

        _store.Purchase("socks");

        message.Should().NotBeNull();
    }
}

Comments

blog comments powered by Disqus