@Test trong Spring Boot

28 tháng 03, 2023 - 691 lượt xem

Học viên: Dương Xuân Vũ
Lớp: Java Fullstack 15
Email: xuanvufb2@gmail.com
Nguồn dịch : https://www.baeldung.com/spring-boot-testing#maven-dependencies

1. Tổng quan

Spring Test là một framework được tích hợp trong Spring Framework, cung cấp cho người lập trình các công cụ để kiểm thử ứng dụng Spring. Spring Test cung cấp các lớp và giao diện để viết các test cases và các integration tests cho ứng dụng Spring.

Trong Bài viết này, chúng ta sẽ xem xét việc viết bài kiểm tra bằng cách sử dụng công cụ trong Spring Boot.

2. Thiết lập Project

Bài viết này chúng ta sẽ tương tác với 1 project là Employee.

3.Dependency

Đầu tiên ta thêm các dependencies vào file pom.xml

<dependency> 
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <version>2.5.0</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>

4. @SpringBootTest

@SpringBootTest là một annotation của Spring Framework trong Java, được sử dụng để viết các test cases cho ứng dụng Spring Boot. Annotation này cung cấp một môi trường test hoàn chỉnh cho việc kiểm tra các thành phần khác nhau của ứng dụng như các lớp service, controller, repository, v.v…

Khi sử dụng @SpringBootTest, Spring Boot sẽ khởi động toàn bộ ứng dụng để thực hiện các test case. Annotation này sẽ tải toàn bộ ứng dụng và các dependency của nó, cung cấp một môi trường test tương đương với môi trường chạy thực tế. Do đó, nó cho phép kiểm tra toàn bộ hệ thống của ứng dụng, chứ không chỉ là một phần nhỏ.

Một số thiết lập bổ sung là cần thiết cho việc này — tất cả điều này đều dễ dàng trong Spring Boot:

@RunWith(SpringRunner.class)
@SpringBootTest(
  webEnvironment = SpringBootTest.WebEnvironment.MOCK,
  classes = Application.class)
@AutoConfigureMockMvc
@TestPropertySource(
  locations = "classpath:application-integrationtest.properties")
public class EmployeeRestControllerIntegrationTest {

    @Autowired
    private MockMvc mvc;

    @Autowired
    private EmployeeRepository repository;

    // write test cases here
}

Chúng ta có thể sử dụng thuộc tính webEnvironment của @SpringBootTest để định cấu hình môi trường thời gian chạy của mình; chúng ta đang sử dụng WebEnvironment.MOCK tại đây để bộ chứa sẽ hoạt động trong môi trường servlet giả.

Tiếp theo, chú thích @TestPropertySource giúp định cấu hình vị trí của các tệp thuộc tính dành riêng cho các thử nghiệm của chúng ta. Lưu ý rằng tệp thuộc tính được tải bằng @TestPropertySource sẽ ghi đè lên tệp application.properties hiện có .

application-integrationtest.properties chứa thông tin chi tiết để định cấu hình bộ lưu trữ :

spring.datasource.url = jdbc:h2:mem:test
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect

Các case test này tương đương với các test của Controller:

@Test
public void givenEmployees_whenGetEmployees_thenStatus200()
  throws Exception {

    createTestEmployee("bob");

    mvc.perform(get("/api/employees")
      .contentType(MediaType.APPLICATION_JSON))
      .andExpect(status().isOk())
      .andExpect(content()
      .contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
      .andExpect(jsonPath("$[0].name", is("bob")));
}

Sự khác biệt so với các bài test của lớp @Controller là toàn bộ chương trình sẽ được thực thi.

5. @TestConfiguration

Như chúng ta đã thấy trong phần trước, một @Test được chú thích bằng @SpringBootTest sẽ khởi động toàn bộ ứng dụng, nghĩa là chúng ta có thể @Autowire bất kỳ @Bean nào được chọn bằng cách quét thành phần vào thử nghiệm của mình:

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

    @Autowired
    private EmployeeService employeeService;

    // class code ...
}

Tuy nhiên, chúng ta có thể tránh khởi động toàn bộ ứng dụng thực mà chỉ chạy một chương trình cần thiết. Chúng ta có thể đạt được điều này với @TestConfiguration . Có hai cách sử dụng annotation.

@RunWith(SpringRunner.class)
public class EmployeeServiceImplIntegrationTest {

    @TestConfiguration
    static class EmployeeServiceImplTestContextConfiguration {
        @Bean
        public EmployeeService employeeService() {
            return new EmployeeService() {
                // implement methods
            };
        }
    }

    @Autowired
    private EmployeeService employeeService;
}

Hoặc :

@TestConfiguration
public class EmployeeServiceImplTestContextConfiguration {
    
    @Bean
    public EmployeeService employeeService() {
        return new EmployeeService() { 
            // implement methods 
        };
    }
}

Các class cấu hình được chú thích bằng @TestConfiguration được loại trừ khỏi quá trình quét thành phần, do đó chúng ta cần nhập nó một cách rõ ràng trong mọi test mà chúng tôi muốn @Autowire nó. Chúng ta có thể làm điều đó với chú thích @Import :

@RunWith(SpringRunner.class)
@Import(EmployeeServiceImplTestContextConfiguration.class)
public class EmployeeServiceImplIntegrationTest {

    @Autowired
    private EmployeeService employeeService;

    // remaining class code
}

6. @MockBean

Một class được đánh dấu @Service sẽ phụ thuộc vào Repository:

@Service
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Override
    public Employee getEmployeeByName(String name) {
        return employeeRepository.findByName(name);
    }
}

Tuy nhiên, để kiểm tra @Service , chúng ta không cần biết hoặc không cần quan tâm đến các lớp implement. Lý tưởng nhất là chúng ta có thể viết và kiểm tra @Service của mình mà không cần kết nối trong lớp implement đầy đủ .

Để đạt được điều này, chúng ta có thể sử dụng @MockBean do Spring Boot Test cung cấp.

Trước tiên chúng ta hãy xem khung của Class test:

@RunWith(SpringRunner.class)
public class EmployeeServiceImplIntegrationTest {

    @TestConfiguration
    static class EmployeeServiceImplTestContextConfiguration {
 
        @Bean
        public EmployeeService employeeService() {
            return new EmployeeServiceImpl();
        }
    }

    @Autowired
    private EmployeeService employeeService;

    @MockBean
    private EmployeeRepository employeeRepository;

    // write test cases here
}

Để kiểm tra @Service , chúng tôi cần tạo một phiên bản của class @Service và có sẵn dưới dạng @Bean để chúng ta có thể @Autowire nó trong class tets của mình. Chúng ta có thể đạt được cấu hình này bằng chú thích @TestConfiguration .

Một điều thú vị khác ở đây là việc sử dụng @MockBean . Nó tạo ra một Mock cho EmployeeRepository , có thể được sử dụng để bỏ qua lệnh gọi đến EmployeeRepository thực tế :

@Before
public void setUp() {
    Employee alex = new Employee("alex");

    Mockito.when(employeeRepository.findByName(alex.getName()))
      .thenReturn(alex);
}

Vì đã setup xong nên test case sẽ đơn giản hơn:

@Test
public void whenValidName_thenEmployeeShouldBeFound() {
    String name = "alex";
    Employee found = employeeService.getEmployeeByName(name);
 
     assertThat(found.getName())
      .isEqualTo(name);
 }

7. @DataJpaTest

Chúng ta sẽ làm việc với một Entity có tên là Employee, có id và tên làm thuộc tính của nó:

@Entity
@Table(name = "person")
public class Employee {

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Long id;

   @Size(min = 3, max = 20)
   private String name;

   // standard getters and setters, constructors
}

Và đây là Repository sử dụng Spring Data JPA:

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {

    public Employee findByName(String name);

}

Bây giờ chúng ta hãy bắt đầu viết class test của chúng ta.
Đầu tiên,tạo bộ khung của class test:

@RunWith(SpringRunner.class)
@DataJpaTest
public class EmployeeRepositoryIntegrationTest {

    @Autowired
    private TestEntityManager entityManager;

    @Autowired
    private EmployeeRepository employeeRepository;

    // write test cases here

}
  • @RunWith(SpringRunner.class) cung cấp cầu nối giữa các tính năng kiểm tra Spring Boot và JUnit. Bất cứ khi nào chúng tôi đang sử dụng bất kỳ tính năng thử nghiệm Spring Boot nào trong các thử nghiệm JUnit của mình, chú thích này sẽ được yêu cầu.
  • @DataJpaTest cung cấp một số thiết lập tiêu chuẩn cần thiết để kiểm tra:

Định cấu hình H2, cơ sở dữ liệu trong bộ nhớ
Cài đặt Hibernate, Spring Data và DataSource
Thực hiện @EntityScan
Bật ghi nhật ký SQL

Để thực hiện các hoạt động DB, chúng tôi cần một số bản ghi đã có trong cơ sở dữ liệu. Để thiết lập dữ liệu này, chúng ta có thể sử dụng TestEntityManager.

Spring Boot TestEntityManager là một giải pháp thay thế cho JPA EntityManager tiêu chuẩn cung cấp các phương thức thường được sử dụng khi viết bài test

EmployeeRepository là thành phần mà chúng ta sẽ kiểm tra.
Bây giờ hãy viết case test đầu tiên:

@Test
public void whenFindByName_thenReturnEmployee() {
    // given
    Employee alex = new Employee("alex");
    entityManager.persist(alex);
    entityManager.flush();

    // when
    Employee found = employeeRepository.findByName(alex.getName());

    // then
    assertThat(found.getName())
      .isEqualTo(alex.getName());
}

Trong Test trên, chúng ta đang sử dụng TestEntityManager để chèn một Nhân viên vào DB và đọc nó qua API tìm theo tên.

Phần assertThat (…) đến từ thư viện Assertj , đi kèm với Spring Boot.

8. @WebMvcTest

Class được đánh dấu @Controller của chúng ta phụ thuộc vào class đánh dấu là @Service vì controller chỉ chứa một phương thức duy nhất được gọi từ @Service- nơi chứa mọi logic

@RestController
@RequestMapping("/api")
public class EmployeeRestController {

    @Autowired
    private EmployeeService employeeService;

    @GetMapping("/employees")
    public List<Employee> getAllEmployees() {
        return employeeService.getAllEmployees();
    }
}

Vì chúng ta chỉ tập trung vào Controller , nên việc mô phỏng mã lớp Service cho các bài kiểm tra đơn vị của chúng ta là điều tự nhiên :

@RunWith(SpringRunner.class)
@WebMvcTest(EmployeeRestController.class)
public class EmployeeRestControllerIntegrationTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private EmployeeService service;

    // write test cases here
}

Để kiểm tra Controller , chúng ta có thể sử dụng @WebMvcTest . Nó sẽ tự động định cấu hình cơ sở hạ tầng Spring MVC cho các bài kiểm tra đơn vị của chúng ta.

Trong hầu hết các trường hợp, @ WebMvcTest sẽ bị giới hạn trong việc khởi động một bộ điều khiển duy nhất. Chúng ta cũng có thể sử dụng nó cùng với @MockBean để cung cấp các triển khai giả cho bất kỳ phụ thuộc bắt buộc nào.

@WebMvcTest cũng tự động định cấu hình MockMvc , cung cấp một cách mạnh mẽ để dễ dàng kiểm tra bộ điều khiển MVC mà không cần khởi động máy chủ HTTP đầy đủ.

Case test của chúng ta:

@Test
public void givenEmployees_whenGetEmployees_thenReturnJsonArray()
  throws Exception {
    
    Employee alex = new Employee("alex");

    List<Employee> allEmployees = Arrays.asList(alex);

    given(service.getAllEmployees()).willReturn(allEmployees);

    mvc.perform(get("/api/employees")
      .contentType(MediaType.APPLICATION_JSON))
      .andExpect(status().isOk())
      .andExpect(jsonPath("$", hasSize(1)))
      .andExpect(jsonPath("$[0].name", is(alex.getName())));
}

Gọi phương thức get(…) có thể được thay thế bằng các phương thức khác tương ứng với các động từ HTTP như put() , post() , v.v. Xin lưu ý rằng chúng ta cũng đang đặt loại nội dung trong yêu cầu.

MockMvc rất linh hoạt và chúng tôi có thể tạo bất kỳ yêu cầu nào bằng cách sử dụng nó.

9. Auto-Configured Tests

Một trong những tính năng tuyệt vời của các chú thích được cấu hình tự động của Spring Boot là nó giúp tải các phần của ứng dụng hoàn chỉnh và các lớp dành riêng cho thử nghiệm của cơ sở mã.

Ngoài các chú thích đã đề cập ở trên, đây là danh sách một vài chú thích được sử dụng rộng rãi:

  • @WebF luxTest : Chúng ta có thể sử dụng chú thích @WebFluxTest để kiểm tra bộ điều khiển Spring WebFlux. Nó thường được sử dụng cùng với @MockBean để cung cấp các triển khai giả cho các phụ thuộc bắt buộc.
  • @JdbcTest : Chúng ta có thể sử dụng chú thích @JdbcTest để kiểm tra các ứng dụng JPA, nhưng đó là cho các kiểm tra chỉ yêu cầu DataSource. Chú thích cấu hình cơ sở dữ liệu nhúng trong bộ nhớ và JdbcTemplate .
  • @JooqTest : Để kiểm tra các bài kiểm tra liên quan đến jOOQ, chúng tôi có thể sử dụng chú thích @JooqTest , cấu hình DSLContext.
  • @DataMongoTest : Để kiểm tra các ứng dụng MongoDB, @DataMongoTest là một chú thích hữu ích. Theo mặc định, nó định cấu hình MongoDB nhúng trong bộ nhớ nếu trình điều khiển có sẵn thông qua các phần phụ thuộc, định cấu hình MongoTemplate, quét các lớp -------- @Document và định cấu hình kho lưu trữ Spring Data MongoDB.
  • @DataRedisTest giúp kiểm tra các ứng dụng Redis dễ dàng hơn. Nó quét các lớp @RedisHash và định cấu hình kho lưu trữ Spring Data Redis theo mặc định.
  • @DataLdapTest định cấu hình LDAP nhúng trong bộ nhớ (nếu có), định cấu hình LdapTemplate , quét các lớp @Entry và định cấu hình kho lưu trữ LDAP Dữ liệu Spring theo mặc định.
  • @RestClientTest : Chúng tôi thường sử dụng chú thích @RestClientTest để kiểm tra các máy khách REST. Nó tự động định cấu hình các phụ thuộc khác nhau như hỗ trợ Jackson, GSON và Jsonb; định cấu hình RestTemplateBuilder; và thêm hỗ trợ cho MockRestServiceServer theo mặc định.
  • @JsonTest : Chỉ khởi tạo bối cảnh ứng dụng Spring với những bean cần thiết để kiểm tra tuần tự hóa JSON.

    10. Kết luận

    Trong bài viết này, chúng ta đã đi sâu vào hỗ trợ thử nghiệm trong Spring Boot và chỉ ra cách viết các bài kiểm tra đơn vị một cách hiệu quả.
    Và nếu bạn muốn tiếp tục tìm hiểu về nó, chúng ta có các bài viết riêng liên quan đến thử nghiệm tích hợp , tối ưu hóa thử nghiệm tích hợp Spring.

Bình luận

avatar
Trịnh Minh Cường 2023-03-28 09:57:49.871787 +0000 UTC

Dịch bài hơi ẩu nên đọc kỹ để hiểu

Avatar
* Vui lòng trước khi bình luận.
Ảnh đại diện
  0 Thích
0