In the world of software development, unit testing is essential for ensuring code quality and efficiency. TestNG, Mockito, and Hamcrest Matchers are powerful tools that, when used together, create robust and maintainable unit tests. In this guide, we will walk you through a step-by-step process to create a TestNG test with Mockito and Hamcrest Matchers.
Prerequisites
Before we begin, ensure you have the following:
- Java Development Kit (JDK) installed
- An Integrated Development Environment (IDE) like IntelliJ IDEA or Eclipse
- Maven or Gradle as your build tool
Dependencies
Add the following dependencies to your Maven or Gradle project:
Maven:
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.4.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
</dependencies>
Gradle:
dependencies {
testImplementation 'org.testng:testng:7.4.0'
testImplementation 'org.mockito:mockito-core:4.1.0'
testImplementation 'org.hamcrest:hamcrest:2.2'
}
Writing a TestNG Test with Mockito and Hamcrest Matchers
For this tutorial, let’s assume we are testing a simple UserService class that has a UserRepository dependency.
Step 1: Create a UserService interface
public interface UserService {
User getUserById(String id);
}
Step 2: Implement the UserService interface
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public User getUserById(String id) {
return userRepository.findById(id);
}
}
Step 3: Create a UserRepository interface
public interface UserRepository {
User findById(String id);
}
Step 4: Implement the UserRepository interface
public class UserRepositoryImpl implements UserRepository {
// Assume the implementation is connecting to a database and fetching the user by id.
@Override
public User findById(String id) {
// Implementation goes here.
return null;
}
}
Step 6: Create a TestNG test class with Mockito and Hamcrest
Create a new test class called UserServiceTest in the appropriate test folder of your project.
import org.mockito.Mockito;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
public class UserServiceTest {
private UserService userService;
private UserRepository userRepository;
@BeforeMethod
public void setUp() {
userRepository = Mockito.mock(UserRepository.class);
userService = new UserServiceImpl(userRepository);
}
@Test
public void getUserById_success() {
// Arrange
String userId = "123";
User expectedUser = new User(userId, "John Doe");
Mockito.when(userRepository.findById(userId)).thenReturn(expectedUser);
// Act
User actualUser = userService.getUserById(userId);
// Assert
Mockito.verify(userRepository).findById(userId);
assertThat(actualUser, equalTo(expectedUser));
}
}
Explanation:
1. Import the necessary Mockito and Hamcrest classes at the beginning of the test class:
import org.mockito.Mockito;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
2. In the setUp() method, which is annotated with @BeforeMethod, create a mock of the UserRepository class and instantiate the UserServiceImpl with the mocked repository. This method runs before each test case:
private UserService userService;
private UserRepository userRepository;
@BeforeMethod
public void setUp() {
userRepository = Mockito.mock(UserRepository.class);
userService = new UserServiceImpl(userRepository);
}
3. Create a test method called getUserById_success() and annotate it with @Test:
@Test
public void getUserById_success() {
// Arrange
String userId = "123";
User expectedUser = new User(userId, "John Doe");
// Act
User actualUser = userService.getUserById(userId);
// Assert
Mockito.verify(userRepository).findById(userId);
assertThat(actualUser, equalTo(expectedUser));
}
4. In the Arrange phase, set up the test data and the expected behavior of the mocked UserRepository by using Mockito’s when() and thenReturn() methods:
String userId = "123";
User expectedUser = new User(userId, "John Doe");
Mockito.when(userRepository.findById(userId)).thenReturn(expectedUser);
5. In the Act phase, call the getUserById() method on the userService instance:
User actualUser = userService.getUserById(userId);
6. In the Assert phase, use Mockito’s verify() method to ensure that the findById() method of the UserRepository was called with the correct argument. Then, use Hamcrest’s assertThat() method along with the equalTo() matcher to compare the expected and actual user objects:
Mockito.verify(userRepository).findById(userId);
assertThat(actualUser, equalTo(expectedUser));
Conclusion
In this guide, we have shown you how to create a TestNG test using Mockito for mocking and Hamcrest Matchers for assertions. By following these steps, you can create efficient and maintainable unit tests for your Java applications, ensuring the quality