1. Unit test là gì? Đặc điểm và lợi ích của Unit test
a) Unit test là gì?
Unit test là một phương pháp kiểm thử phần mềm nhằm kiểm tra tính đúng đắn của một đơn vị nhỏ nhất trong mã nguồn, thường là các hàm hoặc phương thức. Trong unit test, mỗi đơn vị được kiểm tra độc lập với các phần khác để đảm bảo rằng nó hoạt động đúng theo yêu cầu.
b) Đặc điểm của unit test
- Độc lập: Mỗi unit test chỉ kiểm tra một thành phần cụ thể và không phụ thuộc vào các thành phần khác.
- Tự động hóa: Unit test thường được viết dưới dạng mã và chạy tự động.
- Nhanh: Unit test chạy nhanh vì chỉ kiểm tra những phần rất nhỏ của ứng dụng.
c) Lợi ích của unit test
- Phát hiện lỗi sớm: Giúp phát hiện lỗi ngay từ giai đoạn phát triển.
- Dễ bảo trì: Nếu có thay đổi mã, unit test sẽ giúp đảm bảo rằng các phần đã sửa không làm hỏng chức năng cũ.
- Cải thiện thiết kế: Khi viết unit test, bạn có xu hướng viết mã dễ kiểm tra và cấu trúc hơn.
- Tài liệu hóa mã: Unit test có thể hoạt động như một tài liệu, giúp người khác hiểu cách sử dụng các method.
2. Các bước viết Unit Test với Spring Boot
1. Chuẩn bị môi trường
Để viết unit test trong Spring Boot, bạn cần thêm dependency cho JUnit (thường là JUnit 5) và các công cụ liên quan (như Mockito). Nếu bạn sử dụng Spring Boot Starter thì mọi thứ đã được cấu hình sẵn.
– Thêm dependency vào pom.xml (nếu cần):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
Spring Boot Starter Test tích hợp:
- JUnit 5: Framework để viết và chạy unit test.
- Mockito: Thư viện để mock các dependency.
- AssertJ: Thư viện cho các assert mạnh mẽ hơn.
- Hamcrest: Hỗ trợ so khớp điều kiện (matcher).
– Các annotation trong Unit test
@Test
Đánh dấu một phương thức là một test case.@BeforeEach
Thực thi trước mỗi test case (ví dụ: khởi tạo dữ liệu).@AfterEach
Thực thi sau mỗi test case (ví dụ: giải phóng tài nguyên).@SpringBootTest
Khởi chạy Spring context khi kiểm tra tích hợp.@Mock
Tạo một mock object.@InjectMocks
Tự động inject mock vào đối tượng cần kiểm tra.@DisplayName
Gán tên dễ đọc hơn cho test case khi hiển thị kết quả.
2. Xác định đối tượng cần test
Chọn một đơn vị (hàm, lớp, hoặc service) để kiểm tra. ví dụ như sau:
@Service public class UserService { public UserResponse findById(Long id) { log.info("Find user by id: {}", id); UserEntity userEntity = getUserEntity(id); return UserResponse.builder() .id(id) .firstName(userEntity.getFirstName()) .lastName(userEntity.getLastName()) .gender(userEntity.getGender()) .birthday(userEntity.getBirthday()) .username(userEntity.getUsername()) .phone(userEntity.getPhone()) .email(userEntity.getEmail()) .build(); } }
3. Viết Unit Test
Tạo một file test cho lớp bạn muốn kiểm tra. Thông thường, file test sẽ nằm trong thư mục src/test/java.
// Unit test cho service layer @ExtendWith(MockitoExtension.class) // Sử dụng Mockito class UserServiceTest { private UserService userService; private @Mock UserRepository userRepository; private static UserEntity tayJava; @BeforeAll static void beforeAll() { // Dữ liệu giả lập tayJava = new UserEntity(); tayJava.setId(1L); tayJava.setFirstName("Tay"); tayJava.setLastName("Java"); tayJava.setUsername("tayjava"); } @BeforeEach void beforeEach() { // Khởi tạo lớp triển khai của UserService userService = new UserServiceImpl(userRepository); } @Test void testGetUserById_Success() { // Giả lập hành vi repository when(userRepository.findById(1L)).thenReturn(Optional.of(tayJava)); // Gọi hàm và kiểm tra kết quả UserResponse result = userService.findById(1L); Assertions.assertNotNull(result); assertEquals("tayjava", result.getUsername()); } @Test void testGetUserById_Failure() { ResourceNotFoundException thrown = assertThrows(ResourceNotFoundException.class, () -> userService.findById(10L)); assertEquals("User not found", thrown.getMessage()); }
4. Chạy Unit Test
mvn test
– Kết quả in ra (nếu thành công)
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.039 s -- in vn.tayjava.BackendServiceApplicationTests [INFO] [INFO] Results: [INFO] [INFO] Tests run: 18, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 5.384 s [INFO] Finished at: 2024-12-10T15:19:09+07:00 [INFO] ------------------------------------------------------------------------