一、准備工作
1、導入測試依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency>
2、Controller層:
@RestController("/") public class UserController { @Autowired private UserService userService; @RequestMapping public String index(){ return "Hello World!"; } @GetMapping("/user") public ResponseEntity<List<User>> listUser(){ List<User> list = new ArrayList<>(); list.add(new User(1,"張三")); list.add(new User(2,"李四")); return new ResponseEntity(list,HttpStatus.OK); } @GetMapping("/user/{userId}") public ResponseEntity<User> getInfo(@PathVariable("userId") Integer userId){ User user = userService.findByUserId(userId); return new ResponseEntity(user,HttpStatus.OK); } }
3、UserService實現如下:
@Service public class UserServiceImpl implements UserService { @Override public User findByUserId(Integer userId) { return new User(userId,"用戶" + userId); } }
二、測試
1、創建第一個測試用例:
在類上添加@RunWith和@SpringBootTest表示是一個可以啟動容器的測試類
@RunWith(SpringRunner.class) @SpringBootTest //告訴SpringBoot去尋找主配置類(例如使用@SpringBootApplication注解標注的類),並使用它來啟動一個Spring application context;假如不想啟動數據庫相關的配置和類,可以在使用@SpringBootApplication注解標注的類加上exclude=datasourceautoconfiguration.class,datasourcetransactionmanagerautoconfiguration.class屬性 public class UserController01Test { @Autowired private UserController userController; //測試@SpringBootTest是否會將@Component加載到Spring application context @Test public void testContexLoads(){ Assert.assertThat(userController,notNullValue()); } }
2、Spring Test支持的一個很好的特性是應用程序上下文在測試之間緩存,因此如果在測試用例中有多個方法,或者具有相同配置的多個測試用例,它們只會產生啟動應用程序一次的成本。使用@DirtiesContext注解可以清空緩存,讓程序重新加載。
將上面代碼改造如下:在兩個方法上都添加@DirtiesContext注解,運行整個測試類,會發現容器加載了兩次。
3、啟動服務器對Controller進行測試:
這種方式是通過將TestRestTemplate注入進來,進行發送請求測試,缺點是需要啟動服務器。
@RunWith(SpringRunner.class) //SpringBootTest.WebEnvironment.RANDOM_PORT設置隨機端口啟動服務器(有助於避免測試環境中的沖突) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class HttpRequestTest { //使用@LocalServerPort將端口注入進來 @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; @Test public void greetingShouldReturnDefaultMessage() throws Exception { Assert.assertThat(this.restTemplate.getForObject("http://localhost:" + port + "/",String.class), Matchers.containsString("Hello World")); } }
4、使用@AutoConfigureMockMvc注解自動注入MockMvc:
@RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc //不啟動服務器,使用mockMvc進行測試http請求。啟動了完整的Spring應用程序上下文,但沒有啟動服務器 public class UserController02Test { @Autowired private MockMvc mockMvc; /** * .perform() : 執行一個MockMvcRequestBuilders的請求;MockMvcRequestBuilders有.get()、.post()、.put()、.delete()等請求。 * .andDo() : 添加一個MockMvcResultHandlers結果處理器,可以用於打印結果輸出(MockMvcResultHandlers.print())。 * .andExpect : 添加MockMvcResultMatchers驗證規則,驗證執行結果是否正確。 */ @Test public void shouldReturnDefaultMessage() throws Exception { this.mockMvc.perform(get("/")) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().string(containsString("Hello World"))); } }
5、使用@WebMvcTest只初始化Controller層
@RunWith(SpringRunner.class) //使用@WebMvcTest只實例化Web層,而不是整個上下文。在具有多個Controller的應用程序中, // 甚至可以要求僅使用一個實例化,例如@WebMvcTest(UserController.class) @WebMvcTest(UserController.class) public class UserController03Test { @Autowired private MockMvc mockMvc; @Test public void shouldReturnDefaultMessage() throws Exception { this.mockMvc.perform(get("/")) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().string(containsString("Hello World"))); } }
上面的代碼會報錯,因為我們使用@WebMvcTest只初始化Controller層,但是在UserController 中注入了UserService,所以報錯。我們把代碼注釋如下,該測試就會成功了。
但是一般的Controller成都會引用到Service吧,怎么辦呢,我們可以使用mockito框架的@MockBean注解進行模擬,改造后的代碼如下:
@RunWith(SpringRunner.class) //使用@WebMvcTest只實例化Web層,而不是整個上下文。在具有多個Controller的應用程序中, // 甚至可以要求僅使用一個實例化,例如@WebMvcTest(UserController.class) @WebMvcTest(UserController.class) public class UserController03Test { @Autowired private MockMvc mockMvc; //模擬出一個userService @MockBean private UserService userService; @Test public void greetingShouldReturnMessageFromService() throws Exception { //模擬userService.findByUserId(1)的行為 when(userService.findByUserId(1)).thenReturn(new User(1,"張三")); String result = this.mockMvc.perform(get("/user/1")) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) .andExpect(jsonPath("$.name").value("張三")) .andReturn().getResponse().getContentAsString(); System.out.println("result : " + result); } }
本文轉自:https://www.cnblogs.com/caofanqi/p/10836459.html?from=singlemessage