52

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?

Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
gati sahu
  • 2,576
  • 2
  • 10
  • 16
  • 1
    You cannot mock static methods even if you use Mockito. – Abubakkar Jul 07 '17 at 09:21
  • Is there a reason why you do not want to use powermock? – Uwe Allner Jul 07 '17 at 09:25
  • 1
    Do 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](http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/) – Arek Jul 07 '17 at 09:29
  • Those are util class use by other module so I can not change – gati sahu Jul 07 '17 at 09:30
  • 1
    @UweAllner, one reason for not using powermock is Code Coverage tool like JaCoCo may not consider code covered through powermock in code coverage report. – Dexter May 08 '20 at 09:25

4 Answers4

39

(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

Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
  • How 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. – Talha Jun 12 '18 at 07:14
  • 1
    If the class is not final he could subclass `ToBeTested` adding the wrapper method and test the subclass. – thomas77 Sep 19 '18 at 10:53
  • I 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. – 6rchid Jan 23 '19 at 07:42
11

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.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
8

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.

Marc
  • 2,738
  • 1
  • 17
  • 21
  • I 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 Sep 09 '20 at 06:03
  • After 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 org.mockito mockito-inline 3.5.9 – user2000189 Sep 09 '20 at 06:37
  • @user2000189 are you using `SpringBoot`? The latest version of `spring-boot` ( 2.3.3.RELEASE) does not support Mockito 3.4.0. If you want to use it, you need to force `org.mockito:mockito-core` to version 3.4.0. – Marc Sep 09 '20 at 06:38
  • i am using spring-boot (2.3.1-RELEASE) and mockito-core as 3.3.3. – user2000189 Sep 09 '20 at 06:53
  • @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. – Marc Sep 09 '20 at 07:08
  • is there any way we can mock multiple classes in a single try block @Marc – VishnuVS Jun 24 '21 at 07:02
  • The try with block is used so that the object is initialized and cleaned up.So you sure can do something like try (MockedStatic mocked1 = Mockito.mockStatic(Foo1.class); MockedStatic mocked2 = Mockito.mockStatic(Foo2.class) ) { ...... } – David Hladky Jul 21 '21 at 12:47
2

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();
    }
}
Bryce
  • 21
  • 1