JUnit and Mockito: The Perfect Duo for Robust Unit Testing

MadhushaPrasad
6 min readJun 25, 2024

In software development, it’s really important to make sure your code works properly and reliably. That’s where unit testing comes in. Unit testing is like giving each piece of your code a mini-test to ensure it does what it’s supposed to do. For Java developers, two great tools for unit testing are JUnit and Mockito. This article will explain these tools in an easy-to-understand way, highlighting their features and showing you how to use them to write good and maintainable unit tests.

What is unit testing?

Unit testing is when you test the smallest parts of your code, like functions or methods, to make sure they work correctly. Think of it like checking each piece of a puzzle to make sure it fits before you put the whole puzzle together. If each piece works, it’s easier to see if the whole thing will work.

Why is unit testing important?

  1. Catching Errors Early: By testing individual pieces of your code, you can catch mistakes early before they cause bigger problems.
  2. Improves Code Quality: Good unit tests can help you write better code because they force you to think about how your code works and how it can be tested.
  3. Makes Changes Safer: When you change your code, unit tests can help you make sure that your changes don’t break anything.

What is JUnit?

JUnit is a tool that helps you write and run unit tests for your Java code. It provides a framework that makes it easy to create tests, run them, and see the results.

  • Easy to Use: JUnit has a simple way to create tests using special annotations like @Test
  • Automatic Testing: You can run all your tests automatically with one command.
  • Clear Results: JUnit shows you which tests passed and which failed, making it easy to find and fix problems.

What is mockito?

Mockito is another tool that works with JUnit. It’s used for mocking, which means creating fake objects that mimic the behavior of real objects. This is useful when you want to test a piece of your code without relying on other parts.

  • Simulates Real Objects: Mockito lets you create mock objects that act like real objects but are controlled by your tests.
  • Verifies Interactions: You can check if your code interacts with the mock objects in the right way.
  • Simplifies Complex Tests: By using mock objects, you can focus on testing one part of your code without worrying about the rest.

Creating Mock Objects
With Mockito, you can easily create pretend objects using the mock method. These pretend objects can be set up to return specific values or behaviors when their methods are called.


import org.mockito.Mockito;
// Create a mock object
UserService userServiceMock = Mockito.mock(UserService.class);
// Configure the mock object to return a specific value
Mockito.when(userServiceMock.getUserById(1)).thenReturn(new User(1, “John Doe”));

Verification
Mockito provides methods like verify that let you check if specific methods on mock objects were called with the expected arguments. This is really useful for testing how different parts of your code interact.


// Verify that a specific method was called
Mockito.verify(userServiceMock).getUserById(1);

Argument Matchers
Mockito has a lot of argument matches that let you define flexible matching rules for method arguments. This is especially helpful when you need to check method calls with dynamic or complex arguments.


// Verify a method call with any argument
Mockito.verify(userServiceMock).saveUser(Mockito.any(User.class));

Test-Driven Development (TDD) with JUnit and Mockito
Test-Driven Development (TDD) is a way of creating software that emphasizes writing tests before writing the actual code. JUnit and Mockito are great tools for TDD because they provide a solid base for writing and running unit tests.

The TDD Cycle

The TDD cycle includes these steps:

  1. Write a failing test.
  2. Write the minimum code needed to make the test pass.
  3. Refactor the code while making sure all tests pass.

By following this cycle, developers can create well-tested, modular, and maintainable code, ensuring that new features or changes don’t break existing functionality.

Example: Implementing a User Service
Let’s show the TDD cycle by creating a simple UserService class using JUnit and Mockito.

Write a failing test:


import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

public class UserServiceTest {

@Test
public void testGetUserById() {

// Arrange
UserRepository userRepositoryMock = Mockito.mock(UserRepository.class);
when(userRepositoryMock.findById(1)).thenReturn(new User(1, "John Doe"));
UserService userService = new UserService(userRepositoryMock);

// Act
User user = userService.getUserById(1);

// Assert
assertEquals("John Doe", user.getName());
}
}

Write the minimum production code to make the test pass:


public class UserService {

private final UserRepository userRepository;

public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}

public User getUserById(int id) {
return userRepository.findById(id);
}
}

Refactor the code while ensuring all tests pass.

By following the TDD cycle with JUnit and Mockito, developers can build robust and well-tested code step by step, improving code quality and reducing the risk of bugs.

Advanced Topics

While JUnit and Mockito provide a strong foundation for unit testing, there are some advanced topics and features that can make your testing even better.

Parameterized Tests

JUnit supports parameterized tests, allowing you to run the same test with different sets of input data. This is useful for testing methods with various input scenarios.


import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class CalculatorTest {

@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5})

public void testMultiplication(int value) {

Calculator calculator = new Calculator();
int result = calculator.multiply(value, 3);
assertEquals(value * 3, result);

}
}

Behavior-Driven Development (BDD)

Behavior-driven development (BDD) is like TDD but focuses on writing tests in a more natural and readable way, emphasizing the behavior of the system. JUnit supports BDD-style testing through libraries like JBehave and Cucumber.

Integration Testing

While unit tests focus on testing individual components alone, integration tests are designed to test the interaction between multiple components or modules. JUnit can be used with other tools and frameworks, like Spring’s testing utilities or RestAssured for API testing, to help with integration testing.

Test Parallelization

JUnit 5 supports running multiple tests at the same time, which can significantly reduce the overall testing time, especially for larger test suites.


@Execution(ExecutionMode.CONCURRENT)
public class ConcurrentTests {
// …
}

By understanding and using these advanced topics, you can take your testing skills to the next level and create even better software.

How to Use JUnit and Mockito Together

  1. Set Up Your Test Class: Create a new class for your tests and use the@Test annotation to mark your test methods.
  2. Create Mock Objects: Use Mockito to create mock objects for the parts of your code you want to isolate.
  3. Write Your Tests: Write tests that use the mock objects to simulate different scenarios and check if your code behaves correctly.
  4. Run Your Tests: Use JUnit to run all your tests and see the results.

Example

Let’s say you have a class Calculator with a method add that adds two numbers. You can write a unit test for this method using JUnit and Mockito like this:


import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

class CalculatorTest {

@Test
void testAdd() {

Calculator calculator = Mockito.mock(Calculator.class);

Mockito.when(calculator.add(2, 3)).thenReturn(5);

int result = calculator.add(2, 3);

assertEquals(5, result);

}

}

In this example, we use Mockito to create a mock Calculator object and set up theadd method to return 5 when called with 2 and 3. Then, we use JUnit’s assertEquals method to check if the result is correct.

By using JUnit and Mockito together, you can create powerful and flexible unit tests that help you ensure your code works as expected.

and this is my example tutorial on the GitHub repository SpringBootTestingwithJUnit. I will upload all of the Test cases here.

Follow me on GitHub: MadhushaPrasad

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

MadhushaPrasad
MadhushaPrasad

Written by MadhushaPrasad

Open Source Enthusiast | Full Stack Developer👨🏻‍💻 | JavaScript & Type Script , Git & GitHub Lover | Undergraduate — Software Engineering‍💻 | SLIIT👨🏻‍🎓

No responses yet

Write a response