How to mock static method without powermock
Is there any way we can mock the static util method while testing in JUnit?
I know Powermock can mock static calls, but I don't want to use Powermock.
Are there any alternatives?
Solution 1:
(I assume you can use Mockito though) Nothing dedicated comes to my mind but I tend to use the following strategy when it comes to situations like that:
1) In the class under test, replace the static direct call with a call to a package level method that wraps the static call itself:
public class ToBeTested{
public void myMethodToTest(){
...
String s = makeStaticWrappedCall();
...
}
String makeStaticWrappedCall(){
return Util.staticMethodCall();
}
}
2) Spy the class under test while testing and mock the wrapped package level method:
public class ToBeTestedTest{
@Spy
ToBeTested tbTestedSpy = new ToBeTested();
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
@Test
public void myMethodToTestTest() throws Exception{
// Arrange
doReturn("Expected String").when(tbTestedSpy).makeStaticWrappedCall();
// Act
tbTestedSpy.myMethodToTest();
}
}
Here is an article I wrote on spying that includes similar case, if you need more insight: sourceartists.com/mockito-spying
Solution 2:
When you have static code that gives you trouble in your unit tests; so that you feel you have to "mock it away", you have exactly these options:
- You turn to PowerMock(ito). Works fine.
- You turn to JMockit. Works fine, too.
- If you are testing code you have written yourself, you might want to step back and ask yourself: "why did I write code that I now find hard to unit test?"
In other words: if you want to use a mocking framework, you have to use one of those listed above. On the one side, that is absolutely fair. static is one part of the Java language; so why not use a framework that allows you to deal with it?
But of course: you still have the static call in your production code then. Leading to tight coupling, and preventing polymorphism.
So: if you can get rid of the static call (even when just using the workaround suggested in the other answer) - all the better. If not: Mockito can't help; you need the magic of byte code manipulation resp. JVM agents.
Solution 3:
You can use Mockito
(since version 3.4.0) to mock static methods.
Given a class Foo
:
class Foo{
static String method() {
return "foo";
}
}
This is the test:
@Test
void testMethod() {
assertEquals("foo", Foo.method());
try (MockedStatic mocked = Mockito.mockStatic(Foo.class)) {
mocked.when(Foo::method).thenReturn("bar");
assertEquals("bar", Foo.method());
mocked.verify(Foo::method);
}
assertEquals("foo", Foo.method());
}
This requires the dependency org.mockito:mockito-inline:3.4.0
or newer version.
Solution 4:
I've had a lot of luck with doing something similar to what Maciej suggested in his answer above. In Java8 I like to wrap those static methods with functional interfaces to make them more straightforward to inject or mock. For example:
public class MyClass {
private MyStaticWrapper staticWrapper;
public MyClass(final MyStaticWrapper staticWrapper) {
this.staticWrapper = staticWrapper;
}
public void main() {
...
staticWrapper.doSomething();
...
}
}
public interface MyStaticWrapper {
default void doSomething() {
Util.annoyingUntestableStaticFunction();
}
}