Tìm hiểu về Testing trong Spring Boot

4 min read

Trong phát triển phần mềm, việc viết test là một bước quan trọng để đảm bảo rằng ứng dụng hoạt động đúng như mong đợi, và đảm bảo được việc khi một chức năng mới được hoàn thành không ảnh hưởng đến chức năng cũ.

Trong bài viết này sẽ giới thiệu về 2 loại test là unit testintegration test mục đích và cách thực hiện của chúng trong Spring Boot.

1. Unit Test

Unit Test là gì?

Unit test là quá trình kiểm thử các thành phần nhỏ nhất của hệ thống, thường là các method trong các class. Mục tiêu của unit test là kiểm tra tính đúng đắn ủa từng method trong hệ thống mà không bị phụ thuộc bởi các thành phần khác.

Cách thực hiện Unit Test

Trong Spring Boot, unit test thường được thực hiện bằng cách sử dụng các framework như JUnitMockito. JUnit cho phép chúng ta viết các bài test, trong khi Mockito giúp tạo ra các giả lập(mock) để thay thế các phụ thuộc(dependency) thực sự trong quá trình test.

Ví dụ, để test một method trong một service chúng ta có thể viết unit test như sau:

Public class MyService {
    @autowired
    private MyRepository myRepository;

    public MyEntity findById(long id) {
         return myRepository.findById(id);
    }
   
}

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyServiceTest {

    @Mock
    private MyRepository myRepository;

    @InjectMocks
    private MyService myService;

    @Test
    public void testMethod() {
        // Thiết lập dữ liệu giả lập
        when(myRepository.findById(1L)).thenReturn(Optional.of(new MyEntity(1L, "Test")));

        // Gọi phương thức cần kiểm thử
        MyEntity result = myService.findById(1L);

        // Kiểm tra kết quả
        assertEquals("Test", result.getName());
    }
}

Trong ví dụ trên, chúng ta thực hiện:

  • @Mock MyRepository: giả lập một đối tượng MyRepository. Điều này giúp cho việc kiểm soát đối tượng và định nghĩa cách hoạt động của nó trong unit test
  • @InjectMocks MyService: thực hiện inject mock(MyRepository) vào MyService
  • testMethod
    • đầu tiên chúng ta định nghĩa hàng vi của phương thức findById của MyRepository được gọi với tham số đầu vào là 1L
    • MyEntity result = myService.findById(1L): gọi phương thức cần test findById
    • assertEquals(“Test”, result.getName()): kiểm tra kết quả, nếu kết quả trả về sau khi call method khớp với giá trị expect là pass unit test.

Phân biệt Mock và MockBean

Trong Spring boot, @Mock@MockBean là hai cách khác nhau để tạo mock cho các thành phần trong quá trình viết unit test.

  • @Mock: Sử dụng để tạo các mock object phụ thuộc trong service được test. Khi sử dụng @Mock, cần phải khởi tạo Mockito bằng cách sử dụng @RunWith(MockitoJUnitRunner.class) hoặc trong method @Before khai báo MockitoAnnotations.initMocks(this);
@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {

    @Mock
    private MyRepository myRepository;

    @InjectMocks
    private MyService myService;

    @Test
    public void testMethod() {
        // Thiết lập dữ liệu giả lập
        when(myRepository.findById(1L)).thenReturn(Optional.of(new MyEntity(1L, "Test")));

        // Gọi phương thức cần kiểm thử
        MyEntity result = myService.findById(1L);

        // Kiểm tra kết quả
        assertEquals("Test", result.getName());
    }
}
  • @MockBean: sử dụng để tạo các object mock, thường được sử dụng trong integration test. Ví dụ trong các case integration test không thể thực hiện method để trigger đến bên thứ 3 như (AWS,…) chúng ta sẽ sử dụng @MockBean
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyControllerIntegrationTest {

    @MockBean
    private AWSService awsService;

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void testGetEndpoint() {
        // Thiết lập dữ liệu giả lập
        when(awsService.uploadImageToS3()).thenReturn("image/path");

        // Gửi yêu cầu GET đến endpoint
        ResponseEntity<MyResponse> response = restTemplate.getForEntity("/api/my-endpoint", MyResponse.class);

        // Kiểm tra kết quả
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertEquals("Expected Response", response.getBody().getMessage());
    }
}

2. Integration Test

Integration Test là gì?

Integration test là quá trình test các thành phần liên quan kết hợp với nhau, bao gồm việc test thành phần giao tieeos với Database, các service khác. Mục đích của integration test là đảm bảo cho các thành phần hoạt động đúng khi integrate với nhau.

Cách triển khai Integration Test

Trong Spring Boot, Integration Test thường được thực hiện bằng cách sử dụng Spring’s testing support, cho phép chúng ta khởi động một ngữ cảnh ứng dụng (application context) đầy đủ và kiểm thử các thành phần trong ngữ cảnh đó.

Ví dụ, để kiểm thử một Controller trong Spring Boot, chúng ta có thể viết một bài Integration Test như sau:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyControllerIntegrationTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void testGetEndpoint() {
        // Gửi yêu cầu GET đến endpoint
        ResponseEntity<MyResponse> response = restTemplate.getForEntity("/api/my-endpoint", MyResponse.class);

        // Kiểm tra kết quả
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertEquals("Expected Response", response.getBody().getMessage());
    }
}

Kết luận

Unit Test và Integration Test đều là các phần quan trọng trong quá trình phát triển phần mềm. Unit Test giúp kiểm tra tính đúng đắn của từng phần nhỏ, trong khi Integration Test đảm bảo rằng các thành phần hoạt động đúng khi kết hợp với nhau. Sử dụng cả hai loại kiểm thử này trong Spring Boot sẽ giúp đảm bảo rằng ứng dụng của bạn hoạt động ổn định và đúng như mong đợi.

source: https://www.baeldung.com/spring-boot-testing

Avatar photo

Clean Code: Nguyên tắc viết hàm trong lập trình…

Trong quá trình phát triển phần mềm, việc viết mã nguồn dễ đọc, dễ hiểu là yếu tố then chốt để đảm bảo code...
Avatar photo Dat Tran Thanh
3 min read

Leave a Reply

Your email address will not be published. Required fields are marked *