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();
}
}