Façades - Helping you mock the UnMockable
Most of the time working with existing code is hard when you TDD, unless there is an existing contract. If there is an abstract class or interface, lucky you :). Contracts enable us to mock dependencies which is essential when unit testing, as you do not want to test code that you are not actively working on. Also making connections to external dependencies can be very expensive, they have no place in unit tests, we want our tests fast. Testing that you are communicating with external dependencies correctly, falls in the realm of integration and smoke tests.
If you are dealing with a class that you create an instance of then life is easy, just refactor an interface out with the methods that you are going to use. Then use your favorite flavored mocking framework to create a mock of the new interface and inject. Problems arise when you want to mock things that are static or are included in libraries that you don’t control.
The answer is a Façade.
A Façade is a design pattern first identified in the book Design Patterns:
Elements of Reusable Object-Oriented Software.
Just like a Façade on a building it is used to hide details underneath. You can use the Façade pattern to simplify an underlying complex API.
This can help us with our goal of TDD. The Façade can implement a contract that we can use for mocking and we create a concrete type that just passes on the parameters to the method that does the real work. At test time we inject the mocked Façade and at run time we inject the concrete implementation.
As an example I have a Façade for the Language Manager in EpiServer. The Language Manager is not a static class but I don’t control it and it does not implement a contract.
public interface ILanguageManagerFacade
{
string Translate(string key);
}
public class LanguageManagerFacade : ILanguageManagerFacade
{
public string Translate(string key)
{
return LanguageManager.Instance.Translate(key);
}
}
public void SomeTypeTest()
{
// assign
var message = "this is a test message";
var languageManagerFacade = Substitute.For<ILanguageManagerFacade>();
languageManagerFacade.Translate(SomeType.MessageLanguageManagerPath).Returns(message);
var sut = new SomeType(languageManagerFacade);
// act
var result = sut.GetTheMessage();
// assert
Assert.AreEqual(message, result);
}
public class SomeType
{
private readonly ILanguageManagerFacade languageManagerFacade;
public const string MessageLanguageManagerPath = "/Path/To/The/Message";
public SomeType(ILanguageManagerFacade languageManagerFacade)
{
this.languageManagerFacade = languageManagerFacade;
}
public string GetTheMessage()
{
return languageManagerFacade.Translate(MessageLanguageManagerPath);
}
}