Mocking static methods and the Gateway pattern
From AWiki
A year ago I started to use mocking libraries (e.g., Mockito, EasyMock, ...), both for learning something new and for testing purpose in hopeless cases.
Briefly: such a library makes it possible to dynamically redefine the behaviour (return value, thrown exceptions) of the methods of the class under test, in order to run tests in a controlled environment. It makes it possible even to check behavioural expectations for mock objects, in order to test the under test class' interactions with its collaborators.
A few weeks ago a colleague asked me: "[How] can I mock a static method, eventually using a mock library?".
In detail, he was looking for a way to test a class whose code was using a static CustomerLoginFacade.login(String username, String password) method provided by an external API (an authentication custom API by a customer enterprise).
His code appeared as follows:
public class ClassUnderTest {
...
public void methodUnderTest(...) {
...
// check authentication
if(CustomerLoginFacade.login(...)) {
...
} else {
...
}
}
}
but customer's authentication provider was not accessible from test environment: so the need to mock the static login method.
A quick search in the known mocking libraries revealed that:
- EasyMock supports static methods mocking using extensions (e.g, Class Extension, PowerMock)
- JMock doesn't support static method mocking
- Mockito (my preferred [Java] mocking library) doesn't support static method mocking, because Mockito prefers object orientation and dependency injection over static, procedural code that is hard to understand & change (see official FAQ). The same position appears even in a JMock-related discussion.
So, thanks to my colleague, I will analize the more general question "Ho can I handle external / legacy API (e.g., static methods acting as service facade) for testing purpose?". I can identify three different approaches:
- mocking by library: we can use a mocking library supporting external / legacy API mocking (e.g, class' mocking, static methods' mocking), as discussed earlier
- mocking by language: we can refer to the features of a dynamically typed programming language to dynamically change external / legacy API implementation / behaviour. E.g., the login problem discussed earlier can be solved in Groovy style, using the features of a language fully integrated with the Java runtime:
CustomerLoginFacade.metaClass.'static'.login = {
return true;
};
- Architectural approach: mocking by design. This approach refers to a general principle: hide every external (concrete) API behind an interface (i.e.: coding on interfaces, not on concrete implementation). This principle will be more widely discussed in a dedicated article.
So, we can solve my colleague's problem this way: first, we define a login interface:
public interface MyLoginService {
public abstract boolean login(final String username, final String password);
}
Then, we refactor the original methodUnderTest code to use the interface:
public class ClassUnderTest {
private MyLoginService loginService;
// Collaborator provided by Constructor injection (see here for a discussion about injection styles)
public ClassUnderTest(final LoginService loginService) {
this.loginService = loginService;
}
...
public void methodUnderTest(...) {
...
// check authentication
if(loginService.login(...)) {
...
} else {
...
}
}
}
So, for testing pourposes, we can simply inject a fake implementation of the MyLoginService interface:
public void myTest() {
final ClassUnderTest cut = new ClassUnderTest(new FakeLoginService());
cut.methodUnderTest(..., ...);
...
}
where FakeLoginService is simply
public class FakeLoginService implements MyLoginService {
public boolean login(final String username, final String password) {
return true;
}
}
and the real, pruduction implementation of the interface looks simply like this:
public class RealLoginService implements MyLoginService {
public boolean login(final String username, final String password) {
return CustomerLoginFacade.login(username, password);
}
}
In practice, the interface defines an abstract gateway to the external authentication API: changing the gateway implementation, we obtain testing independence from the customer's authentication provider.
IMHO, i prefer the last approach: it's more object oriented, and after all... my colleague called me once the more OO person I know :-). I find this approach more clean and elegant: it's built only upon features of the programming language and doesn't refer to external libraries nor testing-support languages. In terms of design, too, I think it's a more readable and more reusable solution to the problem, which allows a clearer identification of responsibilities of the various pieces of code: MyLoginService defines an interface, and every implementation represents a way to implement it (a real-life (i.e.: production) implementation versus the fake one). Generally, I prefer strongly typed solutions, which allow a more complete compilation-time control over relationships between modules. Mocking solutions, both my library and by language, represent a way to break strong typing, which may lead to out of control situations like so-called [Spaghetti code].
Method mocking (by library or by language, doesn't matter) is in certain, specific situations a very useful technique, too: I'll discuss its application scenario in a later article.
[Incidentally: the solution adopted by my colleague was just that I have proposed (i.e., mocking by design)]
Credits: thanks to Samuele for giving me cause to analyze such a problem (and for our frequent and ever interesting design-related discussion). Thanks to my wife for hers valuable support in writing in English.

