Why doesn't Mockito mock static methods?
JavaMethodsStaticMockitoJava Problem Overview
I read a few threads here about static methods, and I think I understand the problems misuse/excessive use of static methods can cause. But I didn't really get to the bottom of why it is hard to mock static methods.
I know other mocking frameworks, like PowerMock, can do that but why can't Mockito?
I read this article, but the author seems to be religiously against the word static
, maybe it's my poor understanding.
An easy explanation/link would be great.
Java Solutions
Solution 1 - Java
I think the reason may be that mock object libraries typically create mocks by dynamically creating classes at runtime (using cglib). This means they either implement an interface at runtime (that's what EasyMock does if I'm not mistaken), or they inherit from the class to mock (that's what Mockito does if I'm not mistaken). Both approaches do not work for static members, since you can't override them using inheritance.
The only way to mock statics is to modify a class' byte code at runtime, which I suppose is a little more involved than inheritance.
That's my guess at it, for what it's worth...
Solution 2 - Java
If you need to mock a static method, it is a strong indicator for a bad design. Usually, you mock the dependency of your class-under-test. If your class-under-test refers to a static method - like java.util.Math#sin for example - it means the class-under-test needs exactly this implementation (of accuracy vs. speed for example). If you want to abstract from a concrete sinus implementation you probably need an Interface (you see where this is going to)?
Solution 3 - Java
Mockito [3.4.0] can mock static methods!
-
Replace
mockito-core
dependency withmockito-inline:3.4.0
. -
Class with static method:
class Buddy { static String name() { return "John"; } }
-
Use new method
Mockito.mockStatic()
:@Test void lookMomICanMockStaticMethods() { assertThat(Buddy.name()).isEqualTo("John"); try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) { theMock.when(Buddy::name).thenReturn("Rafael"); assertThat(Buddy.name()).isEqualTo("Rafael"); } assertThat(Buddy.name()).isEqualTo("John"); }
Mockito replaces the static method within the
try
block only.
Solution 4 - Java
As an addition to the Gerold Broser's answer, here an example of mocking a static method with arguments:
class Buddy {
static String addHello(String name) {
return "Hello " + name;
}
}
...
@Test
void testMockStaticMethods() {
assertThat(Buddy.addHello("John")).isEqualTo("Hello John");
try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) {
theMock.when(() -> Buddy.addHello("John")).thenReturn("Guten Tag John");
assertThat(Buddy.addHello("John")).isEqualTo("Guten Tag John");
}
assertThat(Buddy.addHello("John")).isEqualTo("Hello John");
}
Solution 5 - Java
Mockito returns objects but static means "class level,not object level"So mockito will give null pointer exception for static.
Solution 6 - Java
I seriously do think that it is code smell if you need to mock static methods, too.
- Static methods to access common functionality? -> Use a singleton instance and inject that
- Third party code? -> Wrap it into your own interface/delegate (and if necessary make it a singleton, too)
That way your own code stays clean, you can mock out all your dependencies in a clean way, and you have an anti corruption layer against external dependencies. I've seen PowerMock in practice and all the classes we needed it for were poorly designed. Also the integration of PowerMock at times caused serious problems
(e.g. https://code.google.com/p/powermock/issues/detail?id=355)
PS: Same holds for private methods, too. I don't think tests should know about the details of private methods. If a class is so complex that it tempts to mock out private methods, it's probably a sign to split up that class...
Solution 7 - Java
In some cases, static methods can be difficult to test, especially if they need to be mocked, which is why most mocking frameworks don't support them. I found http://www.lnbogen.com/2007/07/04/how-to-mock-static-class-or-static-member-for-testing/">this</a> blog post to be very useful in determining how to mock static methods and classes.