1. 程式人生 > >Spring Boot單元測試

Spring Boot單元測試

Spring 框架提供了一個專門的測試模組(spring-test),用於應用程式的整合測試。 在 Spring Boot 中,你可以通過spring-boot-starter-test啟動器快速開啟和使用它。

# pom.xml


12345<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope></dependency
>

1. Junit 測試

當你的單元測試程式碼不需要用到 Spring Boot 功能,而只是一個簡單的測試時,你可以直接編寫你的 Junit 測試程式碼:

12345678public class SimpleJunitTest { @Test public void testSayHi() { System.out.println("Hi Junit."); }}

2. Spring Boot 測試

當你的整合測試程式碼需要用到 Spring Boot 功能時,你可以使用@SpringBootTest註解。
該註解是普通的 Spring 專案(非 Spring Boot 專案)中編寫整合測試程式碼所使用的@ContextConfiguration

註解的替代品。其作用是用於確定如何裝載 Spring 應用程式的上下文資源。

12345678910111213@RunWith(SpringRunner.class)@SpringBootTestpublic class BeanInjectTest { @Autowired private HelloService helloService; @Test public void testSayHi() { System.out.println(helloService.sayHi()); }}
123456789101112@Servicepublic class
HelloService
{ public String sayHi() { return "--- Hi ---"; } public String sayHello() { return "--- Hello ---"; }}

當執行 Spring Boot 應用程式測試時,它會自動的從當前測試類所在的包起一層一層向上搜尋,直到找到一個@SpringBootApplication@SpringBootConfiguration註釋類為止。以此來確定如何裝載 Spring 應用程式的上下文資源。只要你以合理的方式組織你的程式碼,你專案的主配置通常是可以被發現的。本示例專案的部分檔案結構圖為:

123456789101112131415spring-boot-testing-sample\__ src \__ main : \__ java : \__ org : \__ fanlychie : |__ Application.java : \__ service : |__ HelloService.java \__ test \__ java \__ org \__ fanlychie \__ test |__ BeanInjectTest.java

其中,主配置啟動類的程式碼為:

12345678@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class); }}

如果搜尋演算法搜尋不到你專案的主配置檔案,將報出異常:

java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=…) with your test

解決辦法是,按 Spring Boot 的約定重新組織你的程式碼結構,或者手工指定你要裝載的主配置檔案:

1234567@RunWith(SpringRunner.class)@SpringBootTest(classes = {YourApplication.class})public class BeanInjectTest { // ...}

基於 Spring 環境的 Junit 整合測試還需要使用@RunWith(SpringJUnit4ClassRunner.class)註解,該註解能夠改變 Junit 並讓其執行在 Spring 的測試環境,以得到 Spring 測試環境的上下文支援。否則,在 Junit 測試中,Bean 的自動裝配等註解將不起作用。但由於 SpringJUnit4ClassRunner 不方便記憶,Spring 4.3 起提供了一個等同於 SpringJUnit4ClassRunner 的類 SpringRunner,因此可以簡寫成:@RunWith(SpringRunner.class)

3. Spring MVC 測試

當你想對 Spring MVC 控制器編寫單元測試程式碼時,可以使用@WebMvcTest註解。它提供了自配置的 MockMvc,可以不需要完整啟動 HTTP 伺服器就可以快速測試 MVC 控制器。

12345678910111213141516171819import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringRunner.class)@WebMvcTest(HelloController.class)public class HelloControllerTest { @Autowired private MockMvc mvc; @Test public void testHello() throws Exception { mvc.perform(get("/hello")) .andExpect(status().isOk()) .andDo(print()); }}
12345678910@Controllerpublic class HelloController { @GetMapping("/hello") public String hello(ModelMap model) { model.put("message", "Hello Page"); return "hello"; }}

使用@WebMvcTest註解時,只有一部分的 Bean 能夠被掃描得到,它們分別是:

  • @Controller
  • @ControllerAdvice
  • @JsonComponent
  • Filter
  • WebMvcConfigurer
  • HandlerMethodArgumentResolver

其他常規的@Component(包括@Service@Repository等)Bean 則不會被載入到 Spring 測試環境上下文中。

如果測試的 MVC 控制器中需要@ComponentBean 的參與,你可以使用@MockBean註解來協助完成:

12345678910111213141516171819202122232425import static org.mockito.BDDMockito.*;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringRunner.class)@WebMvcTest(HelloController.class)public class HelloControllerTest { @Autowired private MockMvc mvc; @MockBean private HelloService helloService; @Test public void testSayHi() throws Exception { // 模擬 HelloService.sayHi() 呼叫, 返回 "=== Hi ===" when(helloService.sayHi()).thenReturn("=== Hi ==="); mvc.perform(get("/hello/sayHi")) .andExpect(status().isOk()) .andDo(print()); }}
12345678910111213@Controllerpublic class HelloController { @Autowired private HelloService helloService; @GetMapping("/hello/sayHi") public String sayHi(ModelMap model) { model.put("message", helloService.sayHi()); return "hello"; }}

4. Spring Boot Web 測試

當你想啟動一個完整的 HTTP 伺服器對 Spring Boot 的 Web 應用編寫測試程式碼時,可以使用@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)註解開啟一個隨機的可用埠。Spring Boot 針對 REST 呼叫的測試提供了一個 TestRestTemplate 模板,它可以解析連結伺服器的相對地址。

1234567891011121314@RunWith(SpringRunner.class)@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)public class ApplicationTest { @Autowired private TestRestTemplate restTemplate; @Test public void testSayHello() { Map<String, Object> result = restTemplate.getForObject("/hello/sayHello", Map.class); System.out.println(result.get("message")); }}
1234567891011121314@Controllerpublic class HelloController { @Autowired private HelloService helloService; @GetMapping("/hello/sayHello") public @ResponseBody Object helloInfo() { Map<String, Object> map = new HashMap<>(); map.put("message", helloService.sayHello()); return map; }}

5. Spring Data JPA 測試

當你想對 Spring Data JPA 應用進行單元測試時,你可以使用@DataJpaTest註解。並且在進行 JPA 測試時,你可以選擇使用記憶體資料庫還是真實的資料庫測試。

5.1 記憶體資料庫測試

預設情況下,@DataJpaTest使用的是記憶體資料庫進行測試,你無需配置和啟用真實的資料庫。只需要在 pom.xml 配置檔案中宣告如下依賴即可:

# pom.xml


1234<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId></dependency>

@DataJpaTest註解它只掃描@EntityBean 和裝配 Spring Data JPA 儲存庫,其他常規的@Component(包括@Service@Repository等)Bean 則不會被載入到 Spring 測試環境上下文。

123456789101112131415161718@RunWith(SpringRunner.class)@DataJpaTestpublic class UserRepositoryInMemoryTest { @Autowired private UserRepository userRepository; @Test