Table of Contents
- Introduction to Unit Testing
- Setting Up JUnit and Mockito
- Writing Your First Unit Test with JUnit
- Understanding Assertions
- Introduction to Mockito
- Writing Unit Tests Using Mockito
- Mocking and Stubbing Dependencies
- Argument Matchers and Verification
- Best Practices in Unit Testing
- 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.