A Quick Start Guide to Java Unit Testing — Mockito and JUnit 5

A simple guide for junior developer who just started their journey

Photo by me (taken at Thomson Nature Park)
  1. Enforces inversion of control/dependency injection pattern
  2. Pushes developer to write good code (bad code is oftentimes difficult to test and interpret)
  3. Protects your requirements and prevents others from accidentally breaking them.
Table of Contents
— Dependencies Setup
— Sample Project
— Test Naming Convention
— Writing Unit Test
— Mocking Service Object
— Argument Captor for Mocked Object
— Mocking Public Static Method
— Testing Private Method (Reflection)
— Review Test Coverage

Dependencies Setup

To begin, we will use mockito-core, which is sufficient for mocking or partial mocking. Later, there will be examples where we will switch to using mokito-inline.

Sample Project

Let us imagine that we are building a simple message service that can send some string message via email service:

Project Structure for This Demo

Test Naming Convention

There are many common naming conventions when it comes to writing a test case; however, we will not go through all the conventions in this article. You may check them out here to see which is most suitable for your use case:

Writing Unit Test

Below is the basic setup for MessageServiceTest. We will use this class to demonstrate the following ideas:

  • asserting results
  • verifying method calls
  • Captor: This indicates that the ArgumentCaptor object is used to capture the argument values used by mocked object (in this case, by emailService)
  • BeforeEach: This indicates that the init() method will be called each time before each test starts. There are a few more JUnit5 lifecycle annotations for your reference — BeforeAll, AfterEach and AfterAll

Mocking Service Object

Mocking is basically creating a controlled environment for you to fake the response of your mocked object; you are not initializing or calling the actual object. By using the Mock annotation, we are mocking the EmailService behavior.

  • when we call the sendEmailMsg method
  • then result from the method call should be true
  • we also verify that while the method is called, the send method from email service should also be called once
public boolean isServiceActive() {
return false;
}

Argument Captor for Mocked Object

How do we verify that the emailEntity passing to emailService.send() via sendEmailMsg() is sending the expected message?

Mocking Public Static Method

Looking back at the sendEncryptedEmailMsg() method again:

public boolean sendEncryptedEmailMsg(String message) {
if (emailService.isServiceActive()) {
String encryptedMsg;
if (message.length() < 15) {
encryptedMsg = EncryptionUtils.simpleEncrypt(message);
} else {
encryptedMsg = EncryptionUtils.notSoSimpleEncrypt(message);
}

EmailEntity emailEntity = new EmailEntity();
emailEntity.setMessage(encryptedMsg);
emailService.send(emailEntity);
return true;
} else {
return false;
}
}

Testing Private Method (Reflection)

Although testing private method is discouraged (you should probably refactor your code if you really need to test it), there are still techniques that allow us to do so.

Review Test Coverage

Test coverage provides a measurable, but non-exhaustive, metrics on your codebase:

Run Test with Coverage (Intellij)
All the Test Cases are Passed ✔️
Test Coverage Results

Mocking Private Method…?

If you have reached the point where you need to mock private method, it probably means you should consider refactoring the code. Remember to always refer to the SOLID principle. If for some reason that you are not allowed to modify the accessor or refactor the code, yet still want to mock private method and so on, do take a look at PowerMock (highly discouraged).

Full stack developer, Singapore.