Unit Testing with JUnit and Mockito in Java


Table of Contents

  1. Introduction to Unit Testing
  2. Setting Up JUnit and Mockito
  3. Writing Your First Unit Test with JUnit
  4. Understanding Assertions
  5. Introduction to Mockito
  6. Writing Unit Tests Using Mockito
  7. Mocking and Stubbing Dependencies
  8. Argument Matchers and Verification
  9. Best Practices in Unit Testing
  10. Summary

1. Introduction to Unit Testing

Unit testing is the process of testing individual units or components of a software application in isolation to ensure they work as expected. In Java, JUnit is the most popular framework for writing unit tests, and Mockito is the de facto standard for mocking dependencies.

The main goals of unit testing are to:

  • Ensure correctness of individual units (methods/classes)
  • Simplify debugging
  • Improve code quality and reliability
  • Enable refactoring with confidence

2. Setting Up JUnit and Mockito

Using Maven

Add the following dependencies to your pom.xml:

xmlCopyEdit<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.9.1</version>
    <scope>test</scope>
</dependency>

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

Using Gradle

groovyCopyEdittestImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'
testImplementation 'org.mockito:mockito-core:5.2.0'

Also, ensure JUnit 5 is enabled with:

groovyCopyEdittest {
    useJUnitPlatform()
}

3. Writing Your First Unit Test with JUnit

Create a simple class:

javaCopyEditpublic class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

Test it using JUnit:

javaCopyEditimport org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {
    @Test
    void testAddition() {
        Calculator calc = new Calculator();
        assertEquals(5, calc.add(2, 3));
    }
}

4. Understanding Assertions

JUnit provides a variety of assertion methods:

  • assertEquals(expected, actual)
  • assertNotEquals(expected, actual)
  • assertTrue(condition)
  • assertFalse(condition)
  • assertThrows(exception.class, executable)
  • assertAll() — to group multiple assertions

Example:

javaCopyEditassertAll(
    () -> assertEquals(4, calc.add(2, 2)),
    () -> assertNotEquals(5, calc.add(2, 2))
);

5. Introduction to Mockito

Mockito allows you to create mock objects for dependencies. It’s useful when testing service classes that rely on repositories or external systems.

javaCopyEditimport static org.mockito.Mockito.*;

MyRepository mockRepo = mock(MyRepository.class);

6. Writing Unit Tests Using Mockito

Let’s say we have a service class:

javaCopyEditpublic class UserService {
    private final UserRepository userRepository;

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

    public User findUser(String id) {
        return userRepository.findById(id);
    }
}

Test with Mockito:

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

class UserServiceTest {
    @Test
    void testFindUser() {
        UserRepository mockRepo = mock(UserRepository.class);
        User user = new User("1", "Alice");
        when(mockRepo.findById("1")).thenReturn(user);

        UserService service = new UserService(mockRepo);
        User result = service.findUser("1");

        assertEquals("Alice", result.getName());
        verify(mockRepo).findById("1");
    }
}

7. Mocking and Stubbing Dependencies

Mocking allows you to:

  • Replace actual implementations with controlled behavior
  • Simulate exceptions
  • Return dummy values for tests

Example:

javaCopyEditwhen(repository.save(any(User.class))).thenThrow(new RuntimeException("DB Error"));

8. Argument Matchers and Verification

Mockito provides matchers like any(), eq(), contains(), etc.

javaCopyEditverify(repository, times(1)).findById(eq("1"));

You can also capture arguments with ArgumentCaptor.

javaCopyEditArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Bob", captor.getValue().getName());

9. Best Practices in Unit Testing

  • Test one unit of functionality per test case
  • Keep test methods short and focused
  • Use meaningful test method names
  • Don’t overuse mocks—test real behavior where possible
  • Write both positive and negative test cases
  • Ensure tests are independent and deterministic

10. Summary

Unit testing with JUnit and Mockito enables you to build reliable and maintainable Java applications. You can test classes in isolation, mock dependencies, and simulate various scenarios without relying on external systems.