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