Testing your Java code with Mockito

Silas Candiolli
abbeal’s tech blog
5 min readMar 22, 2023
@LightFieldStudios

I’ve been using Mockito for a few years now, and I find it to be a very powerful tool. I see that it would be very complicated to create tests without it. But it wasn’t always easy to use it, not because of Mockito, but because of me. Because test-oriented thinking is difficult at first.

In a practical way, I want to bring examples of using Mockito in real cases of my day-to-day and show how it can help us to test complex code.

What is Mockito?

Mockito is a unit testing framework and its main objective is to instantiate classes and control the behavior of methods. This is called a mock. By mocking the dependency of a class, I make the class I’m testing think it’s actually invoking the method, but in fact, it’s not. As the drawing below tries to explain.

Setting up

Installing Mockito in your project is very simple, as is its use. Following the how-to of the site is very easy to do.

After Mockito is in your project’s dependencies, you can annotate your classes and create mocks. And then you have some ways to test your methods, which may vary depending on your implementation.

For the following examples I used the following libraries:

  • Java 11
  • Mockito 4.7.0
  • JUnit 4.13.2

Summary

  • Mock: creates an instance of a class, but mocked. If you call a method it won’t call the real method unless you want to.
  • Spy: creates an instance of a class, which you can mock or call the real methods. It is an alternative to InjectMocks when you need to mock the methods of the class being tested.
  • InjectMocks: create an instance and inject the necessary dependencies which are annotated with @Mock.
  • Verify: verifies the number of times and which parameters are used to access a given method.
  • When: After a mock is created, you can direct a return to a method given an input parameter.
  • Given: Same purpose as when, but used for BDD. Being part of BDDMockito.
  • Before or BeforeEach: They are annotations used to mark a method that must execute before each test of the class. Typically used for default behaviors across all tests. @Before is for JUnit until version 4 and @BeforeEach is for JUnit 5 or later.

Practicing

At this point, I want to demonstrate the use of Mock/@Mock. With this method, it is possible to instantiate a class dependent on the class you are testing and mock its methods. This is important for unit testing. Because we can isolate the behavior of a method, that’s why they are called unit tests.

When we create tests it is possible to see how complex our code was. Generally, if there are many dependencies in a class, it means that it could be broken into more than one. The same goes for methods.

The division of layers and packages of software exists to reduce coupling and maintain cohesion, making classes and methods have a single responsibility. This makes reading and maintaining the code simpler.

1. Mock | When

In the example below, I created a mock() of the CustomerRegister class to test the behavior of the validateRealCpf method. Evidently, I will get a positive result, regardless of the value I pass to be validated. This is because I used when().

Now, if I call the real method, using Mockito’s thenCallRealMethod(), the test fails. Because the CPF entered is invalid, and my test actually went through the validateRealCpf() method.

2. InjectMocks

I can use mock() in other slightly more complex contexts, such as to get a positive result from repository.save(), regardless of what it receives as an input parameter. In the example below I used the @InjectMocks, @Mock and @Before annotations:

3. Spy

In the following example, I will test using the Spy()/@Spy function, which makes it possible to mock the class being tested. Something you can’t do using just @InjectMocks.

I mean, you can call the real method of the class using @Mock annotation and the when .thenCallRealMethod() function. But this way, you will not create a real instance of the class. Like this:

when(customerRegister.save()).thenCallRealMethod();

But it doesn’t make sense in my case to use @Mock, because I want to mock a method of the same class I’m testing.

Let’s see the example below:

4. Verify

In the example below, I’ll explore some use cases of verify().

You can check the amount of interaction:

verify(customerRegister, times(1)).register(vo);

Check when there is no interaction:

verifyNoInteractions(repository);

Check when there is no interaction other than the ones I already checked, use verifyNoMoreInteractions(), for example:

Conclusion

To conclude, I would like to emphasize the importance of this framework for our daily lives. We all know that testing is necessary, and Mockito is a great tool for that, as being able to isolate behaviors and testing small parts is a great strategy to ensure quality.

The project used in this article is on GitHub. Any questions or feedback about the article, I’m at your disposal.

References

--

--