Spring Boot Test 是 Spring Boot 提供的一個強大測試框架,用於幫助開發者簡化和加速應用程式的單元測試和整合測試。下面是對 Spring Boot Test 各種測試型別和主要註解的詳細教程。
1. Spring Boot Test 的基礎概念
Spring Boot 提供了多種不同層次的測試工具,主要分為以下幾類:
- 單元測試:用於測試單個類的功能,通常會隔離外部依賴,使用 Mockito 等框架來模擬。
- 整合測試:測試多個元件協同工作的情況,通常會啟動部分或全部 Spring 上下文。
- 端到端測試:測試完整的應用,包括資料庫等所有依賴。
Spring Boot Test 框架的核心依賴是 spring-boot-starter-test
,它包含了多種測試框架,如 JUnit、Mockito、AssertJ、Hamcrest 和 JSONassert 等。
2. Spring Boot Test 常用註解
2.1 @SpringBootTest
@SpringBootTest
是 Spring Boot 提供的核心註解,適用於大多數整合測試。它可以啟動完整的 Spring 上下文,模擬一個真實的應用程式環境。
示例:
@SpringBootTest
public class MyApplicationTests {
@Autowired
private SomeService someService;
@Test
public void testServiceMethod() {
assertNotNull(someService);
}
}
常用屬性:
classes
:指定要載入的應用上下文類,通常是主應用類。webEnvironment
:指定 Web 環境型別,可以是NONE
、MOCK
、RANDOM_PORT
或DEFINED_PORT
。
例如,如果我們要在隨機埠啟動 Web 伺服器:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WebApplicationTests {
// 測試程式碼
}
2.2 @MockBean 和 @SpyBean
@MockBean
和 @SpyBean
是 Spring Boot 提供的兩個註解,允許你在測試時模擬和監控 Bean 行為。@MockBean
可以模擬依賴,而 @SpyBean
則會部分使用真實物件。
示例:
@SpringBootTest
public class MyServiceTests {
@MockBean
private SomeDependency someDependency;
@Autowired
private SomeService someService;
@Test
public void testSomeMethod() {
when(someDependency.someMethod()).thenReturn("mocked result");
assertEquals("mocked result", someService.someMethod());
}
}
2.3 @DataJpaTest
@DataJpaTest
是專門為 JPA 相關測試提供的註解。它會配置一個記憶體資料庫(如 H2),並只載入與 JPA 相關的 Bean。
示例:
@DataJpaTest
public class UserRepositoryTests {
@Autowired
private UserRepository userRepository;
@Test
public void testSaveAndFind() {
User user = new User("testUser");
userRepository.save(user);
User foundUser = userRepository.findByUsername("testUser");
assertEquals("testUser", foundUser.getUsername());
}
}
2.4 @WebMvcTest
@WebMvcTest
用於測試 Web 層(通常是 Controller),不載入 Service 和 Repository 層。適合測試請求到 Controller 的對映和驗證等。
示例:
@WebMvcTest(SomeController.class)
public class SomeControllerTests {
@Autowired
private MockMvc mockMvc;
@MockBean
private SomeService someService;
@Test
public void testGetMethod() throws Exception {
when(someService.getSomeData()).thenReturn("mock data");
mockMvc.perform(get("/some-endpoint"))
.andExpect(status().isOk())
.andExpect(content().string("mock data"));
}
}
2.5 @JsonTest
@JsonTest
用於測試 JSON 序列化和反序列化過程。它會載入 JSON 相關的 Bean,如 ObjectMapper
。
示例:
@JsonTest
public class JsonSerializationTests {
@Autowired
private JacksonTester<MyObject> json;
@Test
public void testSerialize() throws IOException {
MyObject myObject = new MyObject("value");
assertThat(this.json.write(myObject)).isEqualToJson("expected.json");
}
}
3. 測試中的 MockMVC 用法
MockMvc
是 Spring 提供的一個測試工具,用於模擬 HTTP 請求並驗證響應。它可以搭配 @WebMvcTest
註解使用,也可以在 @SpringBootTest
環境下手動建立。
示例:
@SpringBootTest
@AutoConfigureMockMvc
public class WebApplicationTests {
@Autowired
private MockMvc mockMvc;
@Test
public void testEndpoint() throws Exception {
mockMvc.perform(get("/api/hello"))
.andExpect(status().isOk())
.andExpect(content().string("Hello World"));
}
}
4. 測試資料的準備和清理
在測試中,通常需要一些初始化資料,Spring Boot 提供了 @Sql
註解,可以在測試開始時執行 SQL 指令碼,此外 @Transactional
註解可以在每次測試結束後自動回滾資料。
示例:
@SpringBootTest
@Transactional
@Sql(scripts = "/test-data.sql")
public class TransactionalTests {
@Autowired
private UserRepository userRepository;
@Test
public void testFindUser() {
User user = userRepository.findByUsername("testUser");
assertNotNull(user);
}
}
5. 測試配置的分離
如果需要為不同環境提供不同的測試配置,可以使用 @ActiveProfiles
註解,指定要載入的配置檔案。
示例:
@SpringBootTest
@ActiveProfiles("test")
public class ProfileBasedTests {
@Autowired
private SomeService someService;
@Test
public void testServiceMethod() {
assertNotNull(someService);
}
}
6. 測試 RestTemplate
如果你的應用依賴 RestTemplate 進行外部 API 呼叫,可以使用 MockRestServiceServer
模擬外部服務。
示例:
@SpringBootTest
public class RestTemplateTests {
@Autowired
private RestTemplate restTemplate;
@Autowired
private RestTemplateBuilder restTemplateBuilder;
private MockRestServiceServer mockServer;
@BeforeEach
public void setup() {
this.mockServer = MockRestServiceServer.createServer(restTemplate);
}
@Test
public void testRestTemplate() {
this.mockServer.expect(requestTo("/some-api"))
.andRespond(withSuccess("response", MediaType.APPLICATION_JSON));
String response = restTemplate.getForObject("/some-api", String.class);
assertEquals("response", response);
}
}
7. 總結
以上介紹了 Spring Boot Test 的主要功能和用法,通常可以從以下幾步開始:
- 單元測試:使用
@MockBean
和Mockito
等工具模擬依賴。 - 整合測試:使用
@SpringBootTest
執行完整的應用上下文。 - Web 層測試:使用
@WebMvcTest
和MockMvc
。 - 資料庫測試:使用
@DataJpaTest
測試 JPA 層。 - 配置分離:使用
@ActiveProfiles
指定不同環境配置。
掌握這些工具和註解後,可以覆蓋 Spring Boot 應用的絕大部分功能測試需求。