Hot questions for Using Mockito in static methods

Hot questions for Using Mockito in static methods

Top 10 Java Open Source / Mockito / static methods

Question:

I have some code that has a static method inside a final class. I was trying to mock that method. I have tried doing a few things..

public final Class Class1{

 public static void doSomething(){
  } 
}

How can I mock doSomething()? I have tried..

Class1 c1=PowerMockito.mock(Class1.class)
PowerMockito.mockSatic(Class1.class);
Mockito.doNothing().when(c1).doSomething();

This gives me an error:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.cerner.devcenter.wag.textHandler.AssessmentFactory_Test.testGetGradeReport_HTMLAssessment(AssessmentFactory_Test.java:63)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, you naughty developer!

    at org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl.performIntercept(MockitoMethodInvocationControl.java:260)

Answer:

Most used testing framework is JUnit 4. So if you are using it you need to annotate test class with:

@RunWith( PowerMockRunner.class )
@PrepareForTest( Class1.class )

Than

PowerMockito.mockSatic(Class1.class);
Mockito.doNothing().when(c1).doSomething();

Mockito.when(Class1.doSomething()).thenReturn(fakedValue);

// call of static method is required to mock it
PowerMockito.doNothing().when(Class1.class);
Class1.doSomething();

Question:

I want to mock an object with Mockito of a class that has some irrelevant static methods.

There are many questions here on stack overflow that explain that mocking static methods is not possible with Mockito. However, the static methods of the object that I need in my unit test are irrelevant for the test.

More concretely, I want to write a unit test for a method that looks for documents in a cache and in case of a cache miss loads them from a Couchbase lite database. Unfortunately the com.couchbase.lite.Document class has some static methods and trying to mock them

Document mockDocument = Mockito.mock(Document.class);

results in a java.lang.UnsatisfiedLinkError. I intend to mock some of the non-static methods e.g.

doReturn("SomeString").when(mockDocument).getString("someKey");

but the static methods are never used, neither in the tested method nor in the unit test itself. Concerning Couchbase, I guess that the library is not particularly relevant for my question, just the fact that I want to mock an object of some library class which contains both, irrelevant static as well as relevant non-static methods.

Update: Here is the stack trace

java.lang.UnsatisfiedLinkError: com.couchbase.lite.internal.core.C4Log.setLevel(Ljava/lang/String;I)V

at com.couchbase.lite.internal.core.C4Log.setLevel(Native Method)
at com.couchbase.lite.FileLogger.setupDomainObjects(FileLogger.java:84)
at com.couchbase.lite.FileLogger.<init>(FileLogger.java:47)
at com.couchbase.lite.Log.<init>(Log.java:35)
at com.couchbase.lite.AbstractDatabase.<clinit>(AbstractDatabase.java:80)
at com.couchbase.lite.internal.support.Log.sendToLoggers(Log.java:401)
at com.couchbase.lite.internal.support.Log.e(Log.java:247)
at com.couchbase.lite.NativeLibraryLoader.load(NativeLibraryLoader.java:41)
at com.couchbase.lite.Document.<clinit>(Document.java:42)
at sun.reflect.GeneratedSerializationConstructorAccessor10.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:19)
at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:47)
at org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:25)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:63)
at org.mockito.Mockito.mock(Mockito.java:1910)
at org.mockito.Mockito.mock(Mockito.java:1819)
at com.my.app.ClassOfTheTest.nameOfTheTest(ClassOfTheTest.java:1234)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)

Answer:

Create a DocumentUtils class for these static methods, that way if you wanted to use these methods in the UnitTest you can still do so without mocking it.

DocumentUtils.someMethod(args);

Update:

How the DocumentUtils class may look like (Added some imaginary static methods that likely have no relevance to your use-case) :

public final class DocumentUtils {

public static boolean isDocumentReadable(Document doc) {
    ...
}

public static boolean isDocumentWrittenInEnglish(Document doc) {
    ...
}

public static List<Document> getEnglishWrittenDocuments(List<Document> docs) {
    ...
}

public static boolean areDocumentsTheSame(Document doc1, Document doc2) {
    ...
}

}

Tests:

When it comes to testing you may not even need to reference this class at all...

You will however, need to ensure the mocked Document object that is going to be passed to these methods one way or another, will return the expected value.

For example, if DocumentUtils.isDocumentWrittenInEnglish(Document doc) were to be called at some stage, the mock has to be setup to return the expected value beforehand:

when(mockedDocument.getLanguage()).thenReturn(LANGUAGE_ENGLISH);

Question:

I'm writing a test case to test a component that invokes a static method accepting 5 arguments. I want to know how I can do that.

Earlier I have been successful in mocking static method with 0 and 1 arguments. However when I mock a static method with more than 1 argument, it returns null. Following is a simplified version of what I'm trying to do. The static method has 2 arguments.

public interface VO {

}
public class A implements VO {
    private int value = 5;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}
public class Factory {
    public static VO getObj(String a, String b) {
        return new A();
    }
}
@RunWith(PowerMockRunner.class)
@PrepareForTest({com.csc.fsg.nba.vo.Factory.class})
public class APITest {


    @BeforeClass
    public static void runOnceBeforeClass() throws Exception {
        System.out.println("Executing runOnceBeforeClass()");
        A a = new A();
        a.setValue(3);
        PowerMockito.mockStatic(Factory.class);
        Mockito.when(Factory.getObj(Mockito.any(String.class), Mockito.any(String.class))).thenReturn(a);
    }

    @Test
    public void testA() throws Exception {
        VO vo = Factory.getObj("a", null);
        System.out.println(((A)vo).getValue());
    }

}

I'm expecting that sysout should print 3, however vo is null.


Answer:

In this particular case the any(String.class) fails to match the null passed when exercising the test

//...

VO vo = Factory.getObj("a", null);

//...

Use anyString()

//...

when(Factory.getObj(anyString(), anyString())).thenReturn(a);

Question:

I have following jar in my project and I haven't seen any problems up to now:

mockito-all-1.10.19.jar

Due to project maturity I am not able to shift to newer Mockito version.

I am lacking any*() methods that I need: these are anyObject() and anyString(). These are static methods of Mockito 2.2.7 API. Are they missing in 1.10 version and subversions.

Source: https://static.javadoc.io/org.mockito/mockito-core/2.2.7/org/mockito/ArgumentMatchers.html#anyList()

How can I replace those methods - maybe there had been present some deprecated methods I could use?


Answer:

You should use:

any(Object.class);
any(String.class);

https://static.javadoc.io/org.mockito/mockito-core/1.10.19/org/mockito/Matchers.html#any(java.lang.Class)

Since Mockito extends Matchers you can get all the matchers with:

import static org.mockito.Mockito.*

... which is the style recommended by Mockito.

Question:

I have a class where I'm using Powermock + Mockito to suppress a static method in a utility class. It works fine with Powermock 1.6.2 and Mockito 1.10.19, but I've been tasked with moving to Java 10 (JRE: we're still compiling with Java 8) and so I've moved to Powermock 2 (currently in beta) and Mockito 2.16.1. Now, I consistently get org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Misplaced or misused argument matcher detected here.

A simple example, MyMockito.java:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.lang.reflect.Method;

import static org.mockito.Mockito.any;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.support.membermodification.MemberMatcher.method;
import static org.powermock.api.support.membermodification.MemberModifier.suppress;

@RunWith(PowerMockRunner.class)
@PrepareForTest(StringMeasurer.class)
public class MyMockito {
    @Test
    public void testSuppressMethod() throws Exception {
        spy(StringMeasurer.class);
        Method measure = method(StringMeasurer.class, "measure", String.class);
        suppress(measure);
        when(StringMeasurer.class, measure)
                .withArguments(any(String.class))
                .thenReturn(10);
        System.out.println(StringMeasurer.measure("Hello"));
    }

And StringMeasurer.java:

    public class StringMeasurer {
        private StringMeasurer() {}
        public static int measure(String s) {
            return s.length();
        }
    }
}

I'm assuming that either there have been some changes to how matchers can be used to match arguments in stubbed static methods, or else this should never have worked and somehow got through in Mockito 2 (or possibly this is a bug in the Powermock beta). Can anyone provide me some insight into what I'm doing wrong?


Answer:

Working solution for PowerMock 2.0.0-beta.5:

import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.when;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(StringMeasurer.class)
public class MyMockito {
    @Test
    public void testSuppressMethod() throws Exception {
        PowerMockito.mockStatic(StringMeasurer.class);
        when(StringMeasurer.measure(any(String.class))).thenReturn(10);
        System.out.println(StringMeasurer.measure("Hello"));
    }
}

More details can be found in the official PowerMock documentation: Mocking Static Method

Question:

I'm writing integration test on a RestController in SpringBoot. Normally I would run with SpringRunner.class, but when it comes to Mock a static method I need to use PowerMock.

The strange fact is that when I run the single tests, they individually pass (but returns error messages), when I try to run the entire test class, no test passes and it returns the same error message.

@RunWith(PowerMockRunner.class)
@PrepareForTest({JwtUtils.class})
//@PowerMockRunnerDelegate(SpringRunner.class) THIS DOESN'T WORK!!!
@SpringBootTest(classes = SpringBootJwtApplication.class)
public class RestAccessIntegrationTest {

  @Autowired @InjectMocks
  RestController restController;

  @Mock
  HttpServletRequest request;

  @Test
  public void operationsPerAccountWhenSuccessfulTest(){
    mockStatic(JwtUtils.class);
    when(JwtUtils.myMethod(request)).thenReturn("blabla");
    String expected = ... ;
    String actual = restController.getOperations();
    assertEquals(actual, expected);
  }

}

If I run the test or the entire class I get an error of this type:

Exception in thread "main" java.lang.NoSuchMethodError: org.powermock.core.MockRepository.addAfterMethodRunner(Ljava/lang/Runnable;)at org.powermock.api.mockito.internal.mockcreation.MockCreator.mock(MockCreator.java:50)

If I uncomment @PowerMockRunnerDelegate(SpringRunner.class) there it comes this other error:

Exception in thread "main" java.lang.NoClassDefFoundError: org/powermock/core/testlisteners/GlobalNotificationBuildSupport$Callback at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.run(DelegatingPowerMockRunner.java:139)


Answer:

In the when method, try using any(HttpServletRequest.class) instead of the request mock object. Also use MockHttpServletRequest instead of mocking HttpServletRequest. This should work,

@RunWith(PowerMockRunner.class)
@PrepareForTest(JwtUtils.class)
@PowerMockIgnore( {"javax.management.*"})
public class RestAccessIntegrationTest {

    @InjectMocks
    private RestController restController;

    private MockHttpServletRequest request;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        request = new MockHttpServletRequest();
        RequestContextHolder.setRequestAttributes(
                new ServletRequestAttributes(request));
    }

    @Test
    public void operationsPerAccountWhenSuccessfulTest() {
        mockStatic(JwtUtils.class);
        when(JwtUtils.myMethod(any(HttpServletRequest.class)))
           .thenReturn("blabla");

        String expected = ... ;
        // does your getOperations take HttpServletRequest
        // as parameter, then controller.getOperations(request);
        String actual = restController.getOperations();
        assertEquals(actual, expected);
    }
}

Question:

I have a method like this.

 public Response post(String json) {

   EventList list = Recorder.getRecorders();
   if (null == list || list.isEmpty()) {
     throw new ServiceUnavailableException("An Recorder is either not configured");
  }
  String targetIUrl = list.getNext().getBase();
  String targetV2Url = targetUrl + "/v2";

 // other processes......
}
  1. I want to mock Recorder.getRecorder() and do something like when(Recorder.getRecorder()).thenReturn(null) and test if throw a 503 exception. But getRecorder() is a static method. I know Mockito cannot mock the static method, but I still wanna know if it is possible to change some code made this testable without using Powermock or other libraries.

  2. If I mock Recorder, do I have to change the method to post(String json, Recorder recorder)? Otherwise, how can I make this mock interact with the method?


Answer:

If you want to mock the getRecorders() behaviour without using a library for mocking static methods (such as Powermock) then you'll have to extract the static call from inside post(). There are a few options for this:

  1. Pass the EventList into post()

    public post(String json, EventList list) {
        ...
    }
    
  2. Inject the EventList into the class which contains post()

    public class TheOneThatContainsThePostMethod {
        private EventList eventList;
    
        public TheOneThatContainsThePostMethod(EventList eventList) {
            this.eventList = eventList;
        }
    
        public post(String json) {
            if (null == this.eventList || this.eventList.isEmpty()) {
                throw new ServiceUnavailableException("An Recorder is either not configured");
            }
        }
    }
    
  3. Hide the static method call inside another class and inject an instance of that class into post() or the class which contains post(). For example:

    public class RecorderFactory {
        public EventList get() {
            return Recorder.getRecorders();
        }
    }
    
    public class TheOneThatContainsThePostMethod {
        private RecorderFactory recorderFactory;
    
        public TheOneThatContainsThePostMethod(RecorderFactory recorderFactory) {
            this.recorderFactory = recorderFactory;
        }
    
        public post(String json) {
            EventList list = recorderFactory.getRecorders();
            ...
        }
    }
    
    // Or ...
    
    public post(String json, RecorderFactory recorderFactory) {
        EventList list = recorderFactory.getRecorders();
        ...
    }
    

With the first two approaches your test can simply invoke post() providing (1) a null EventList; (2) an empty EventList ... thereby allowing you to test the 'throw a 503 exception' behaviour.

With the third approach you can use Mockito to mock the behaviour of the RecorderFactory to return (1) a null EventList; (2) an empty EventList ... thereby allowing you to test the 'throw a 503 exception' behaviour.