Pleasant JUnits with Mockito

Vaibhav Hajela
4 min readFeb 6, 2021

Testing the smallest piece of code that can be logically isolated in a system

Developer can do quick and flexible test of his change.

Annotations:

@Test — Identifies a method as a test method.

@Before — Executed before each test. It is used to prepare the test environment (e.g., read input data, initialize the class).

@After — Executed after each test. It is used to cleanup the test environment (e.g., delete temporary data, restore defaults). It can also save memory by cleaning up expensive memory structures.

@BeforeClass — Executed once, before the start of all tests. It is used to perform time intensive activities, for example, to connect to a database. Methods marked with this annotation need to be defined as static to work with JUnit.

@AfterClass — Executed once, after all tests have been finished. It is used to perform clean-up activities, for example, to disconnect from a database. Methods annotated with this annotation need to be defined as static to work with JUnit.

@Ignore or @Ignore(“Why disabled”) — Marks that the test should be disabled. This is useful when the underlying code has been changed and the test case has not yet been adapted. Or if the execution time of this test is too long to be included. It is best practice to provide the optional description, why the test is disabled.

MOCKITO

WHY MOCK?

Most classes have dependencies.

Methods delegates some of the work to other methods in other classes, and we call these classes dependencies.

When unit testing such methods, our tests will also depend on those methods as well.

We want the unit tests to be independent of all other dependencies.

What is mockito?

Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produce clean verification errors.

You need to add this dependency to your pom.xml file.

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.8.9</version>
<scope>test</scope>
</dependency>

HOW TO INJECT MOCKS?

Mockito Annotations

Before hitting the keyboard to write application and unit tests, let’s quickly overview the useful mockito annotations.

  • @Mock is used for mock creation. It makes the test class more readable.
  • @Spy is used to create a spy instance. We can use it instead spy(Object) method.
  • @InjectMocks is used to instantiate the tested object automatically and inject all the @Mock or @Spy annotated field dependencies into it (if applicable).
  • @Captor is used to create an argument captor

I SPY — MOCKITO SPY

Why spy?

  • Sometimes we do need to call real methods of a dependency but still want to verify or track interactions with that dependency, this is where we would use a spy.
  • When a field is annotated with @Spy, Mockito will create a wrapper around an actual instance of that object and therefore we can call real implementation and also verify interactions at the same time.
  • Some of the behavior of a spy could be mocked if neened.
  • in the example we will discuss, the dependency behavior is not mocked but still it’s interactions are verified.

@Spy Annotation

@Spy
List<String> spyList = new ArrayList<String>();
@Test
public void whenUsingTheSpyAnnotation_thenObjectIsSpied() {
spyList.add("one");
spyList.add("two");
Mockito.verify(spyList).add("one");
Mockito.verify(spyList).add("two");
assertEquals(2, spyList.size());
}

Stubbing a Spy

doReturn() to override the size() method:

@Test
public void whenStubASpy_thenStubbed() {
List<String> list = new ArrayList<String>();
List<String> spyList = Mockito.spy(list);
assertEquals(0, spyList.size()); Mockito.doReturn(100).when(spyList).size();
assertEquals(100, spyList.size());
}

Simple Mocking and Verifying

Void methods can be used with Mockito’s doNothing(), doThrow(), and doAnswer() methods, making mocking and verifying intuitive:

@Test
public void whenAddCalledVerified() {
MyList myList = mock(MyList.class);
doNothing().when(myList).add(isA(Integer.class), isA(String.class));
myList.add(0, "");

verify(myList, times(1)).add(0, "");
}

However, doNothing() is Mockito’s default behavior for void methods.

This version of whenAddCalledVerified() accomplishes the same thing as the one above:

@Test
public void whenAddCalledVerified() {
MyList myList = mock(MyList.class);
myList(0, "");

verify(myList, times(1)).add(0, "");
}

DoThrow() generates an exception:

@Test(expected = Exception.class)
public void givenNull_AddThrows() {
MyList myList = mock(MyList.class);
doThrow().when(myList).add(isA(Integer.class), isNull());

myList.add(0, null);
}

We’ll cover doAnswer() below.

Argument Capture

One reason to override the default behavior with doNothing() is to capture arguments.

In the example above, we used the verify() method to check the arguments passed to add().

However, we may need to capture the arguments and do something more with them.

In these cases, we use doNothing() just as we did above, but with an ArgumentCaptor:

@Test
public void whenAddCalledValueCaptured() {
MyList myList = mock(MyList.class);
ArgumentCaptor<String> valueCapture = ArgumentCaptor.forClass(String.class);
doNothing().when(myList).add(any(Integer.class), valueCapture.capture());
myList.add(0, "captured");

assertEquals("captured", valueCapture.getValue());
}

Answering a Call to Void

A method may perform more complex behavior than merely adding or setting value.

For these situations, we can use Mockito’s Answer to add the behavior we need:

@Test
public void whenAddCalledAnswered() {
MyList myList = mock(MyList.class);
doAnswer(invocation -> {
Object arg0 = invocation.getArgument(0);
Object arg1 = invocation.getArgument(1);

assertEquals(3, arg0);
assertEquals("answer me", arg1);
return null;
}).when(myList).add(any(Integer.class), any(String.class));
myList.add(3, "answer me");
}

--

--