- Step one is to mock your class (or Interface)
TestClass mockedObject = mock(TestClass.class);
⚠️ By default, all methods of a mock return “uninitialized” or “empty” values, e.g., zeros for numeric types (both primitive and boxed), false for booleans, and nulls for most other types.
Now, you can specify what to return when the method is called. Mockito supports two different ways:
2a. Now that the mock is created, you can mock the object
when(mockedObject.method()).thenReturn(WhatYouWantToReturnHere);
2b. Now that the mock is created, you can mock the object
doReturn(WhatYouWantToReturnHere).when(mockedObject).method());
⚠️ doReturn has no type checking in the compile time. Read more about the differences between when-thenReturn and doReturn-when at the link below
http://sangsoonam.github.io/2019/02/04/mockito-doreturn-vs-thenreturn.html
These verify methods are generally used to check/unit test the "side-effects" of void return type methods.
- Check if some method was called
verify(mockedcObject).method(methodParameters);
- Check if some method is never called
verify(mockedObject, never()).method(methodParameters);
- Check the number of times a method is called (N = number of times you want to verify method called)
verify(mockedObject, times(N)).method(methodParameters);
You can use argument matchers when you need flexible verification or stubbing. Use it when you don't want to hardcode method arguments and need the mocked method to respond to a wider range of values or beforehand unknown values.
Some common argument matchers are:
- anyBoolean()
- anyInt()
- anyString()
- any() (for any Objects)
Example:
when(mockedList.get(anyInt())).thenReturn("element");
Sometimes you want to write a unit test for verify a method throws an exception for certain edge cases. The typical structure is:
@Test(expected=MyException.class)
public void testingMethodThrowsException() {
when(mockedObject.method()).thenThrow(new MyException("my exception message here"));
}
You can test this with a common exception like NullPointerException.class
Used for checking the values passed to a mocked method.
- Declare Argument Captor (i.e. for capturing a String argument)
ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
- Define Argument Captor on method
verify(mockedOjbect).method(stringArgumentCaptor.capture());
- Capture the argument
assertThat(stringArgumentCaptor.getValue(), is("ExpectedCapturedValue"));
Used when you want to override some logic, but want to retain all other functionality of a class. Code below would fail if just using standard mock for ArrayList because add()
method would do nothing to the mocked object, and size()
would return 0 even after adding. However, when using a Spy, it is not a mocked object but a real ArrayList and all other class logic/functionality is retained and thus calling add()
on this ArrayList increases its size and the test passes.
// Using regular Mock. Test fails
List arrayListSpy = mock(ArrayList.class);
assertEquals(0 , arrayListSpy.size());
arrayListSpy.add("Dummy");
assertEquals(1, arrayListSpy.size()); // Returns 0
// Using Mockito Spys. Test passes
List arrayListSpy = spy(ArrayList.class);
assertEquals(0 , arrayListSpy.size());
arrayListSpy.add("Dummy");
assertEquals(1, arrayListSpy.size()); // Returns 1
You'll need PowerMockito for mocking static or private methods. All repos will already have it declared as a dependency, so you can start using it right away.
There are more overloaded variations of Whitebox.invokeMethod(), but this is one commonly used example:
Whitebox.invokeMethod(mockedObject, "privateMethodName", method arguments...);
- Specify the Runner and Prepare the class for mocking. Add the annotations below to the Unit Test Class you created, above your class declaration:
@PrepareForTest({ ClassThatContainsStaticMethod.class })
@RunWith(PowerMockRunner.class)
public class MyUnitTest {
// blah
}
- Mock your class that contains static method using PowerMockito API
ClassThatContainsStaticMethod mockedObject = PowerMockito.mockStatic(ClassThatContainsStaticMethod.class);
- Mock the object as before
when(ClassThatContainsStaticMethod.staticMethod()).thenReturn(WhatYouWantToReturnHere);
- Prepare class that makes use of constructor
@PrepareForTest({ ClassThatIsUsingConstructor.class })
@RunWith(PowerMockRunner.class)
public class MyUnitTest {
// blah
}
PowerMockito.whenNew(ClassOfConstructor.class).withAnyArguments().thenReturn(mockClassOfConstructor);
@PrepareForTest(DAO.class)
@RunWith(PowerMockRunner.class)
public class VerifyTest {
@Test
public void verifyTest() {
// Object under test
UnderTest obj = new UnderTest();
// Mock
PowerMockito.mockStatic(DAO.class);
// Execute method under test
obj.foo();
// Test; default to verifying a single call
PowerMockito.verifyStatic();
DAO.executeSQL();
}
}
// prev: Mockito, PowerMockito, Whitebox, etc. imports
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestClass{
private static Logger logger = mock(Logger.class);
@BeforeClass
public static void init(){
Whitebox.setInternalState(ClassImTesting.class, "log", logger);
}
@AfterClass
public static void uninit(){
Whitebox.setInternalState(ClassImTesting.class, "log", LoggerFactory.getLogger(ClassImTesting.class));
}
@Before
public void setUp(){
Mockito.reset(logger);
}
@Test
public void methodToTest(){
ClassImTesting.methodImTesting();
Mockito.verify(logger, Mockito.times(1)).error("the error");
Mockito.verify(logger, Mockito.times(1)).info(anyString()); // etc.
}
// for test that's expected to throw an exception:
@Test
public void throwExceptionTest(){
try{
methodImTesting();
}
catch(Exception e){
assertEquals("expected message", e.getMessage());
}
Mockito.verify(logger, Mockito.times(1)).warn(anyString(), anyInt(), anyInt());
}
}
PowerMockito.mockStatic(Thread.class);
doNothing().when(Thread.class, "sleep", anyLong());
Whitebox.setInternalState(Foo.class, "FIELD_NAME", "value");
java.lang.NullPointerException
Usually means something didn't get mocked in the method you're trying test
org.mockito.exceptions.misusing.InvalidUseOfMatchersException
When you use an argument matcher for one of the arguments, all the other arguments must also use an argument matcher, so something like:
when(mockedObject.method(anyString(), "Test1234").thenReturn(WhatYouWantToReturnHere);
would throw this exception because the method has an argument matcher as the first parameter, however uses a String type for the second parameter.