How to mock static method without powermock
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();
}
}
Related videos on Youtube
gati sahu
Updated on July 25, 2022Comments
-
gati sahu almost 2 years
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?
-
Abubakkar almost 7 yearsYou cannot mock static methods even if you use Mockito.
-
Uwe Allner almost 7 yearsIs there a reason why you do not want to use powermock?
-
Arek almost 7 yearsDo you have to mock it? Is it your code and you can rewrite it so that there will be no statics? Static methods are death to testability
-
gati sahu almost 7 yearsThose are util class use by other module so I can not change
-
GhostCat almost 6 yearsI noticed that your question is still "open" - as you didn't accept an answer. Please have a look and decide if you want to accept an answer. Or let me know if there is something I can do to enhance my input to make it accept worthy. Accepting helps future readers to determine if the problem is solved, and shows appreciation for the people who took the time answering you. Thanks!
-
Dexter about 4 years@UweAllner, one reason for not using powermock is Code Coverage tool like JaCoCo may not consider code covered through powermock in code coverage report.
-
-
Talha about 6 yearsHow can you call constructor when the question clearly ask about static methods? Wouldn't it be useless to call constructor when all methods are static? Also spying will also be useless in this case.
-
thomas77 almost 6 yearsIf the class is not final he could subclass
ToBeTested
adding the wrapper method and test the subclass. -
6rchid over 5 yearsI get an error
Wanted but not invoked:
Actually, there were zero interactions with this mock.
when I try to verify whether the method was called. -
user2000189 almost 4 yearsI used org.mockito:mockito-inline:3.4.0 and newer version and copied the same code as above. But still i get compilation error for "MockedStatic" and "mockStatic". it does not show any import statements. I tried using import org.mockito.*; but it does not work
-
user2000189 almost 4 yearsAfter using the edited answer as well, i am getting compilation error as "MockedStatic cannot be resolved to a type". Do we need any special import statements. My pom.xml dependecy added as <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>3.5.9</version> </dependency>
-
Marc almost 4 years@user2000189 are you using
SpringBoot
? The latest version ofspring-boot
( 2.3.3.RELEASE) does not support Mockito 3.4.0. If you want to use it, you need to forceorg.mockito:mockito-core
to version 3.4.0. -
user2000189 almost 4 yearsi am using spring-boot (2.3.1-RELEASE) and mockito-core as 3.3.3.
-
Marc almost 4 years@user2000189 forcing
mockito-core
to version 3.4.0 will let you run this example, but be aware of other potential issues since it's not yet officially supported by Spring. -
Mousumi Kar over 3 yearshello , do you have a example of unit testing for this please ?
-
VishnuVS about 3 yearsis there any way we can mock multiple classes in a single try block @Marc
-
David Hladky almost 3 yearsThe try with block is used so that the object is initialized and cleaned up.So you sure can do something like try (MockedStatic<Foo1> mocked1 = Mockito.mockStatic(Foo1.class); MockedStatic<Foo2> mocked2 = Mockito.mockStatic(Foo2.class) ) { ...... }