SpringBoot測試Controller層

1、準備工做

  一、導入測試依賴html

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

  二、Controller層:java

@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); } }

  三、UserService實現以下:git

@Service public class UserServiceImpl implements UserService { @Override public User findByUserId(Integer userId) { return  new User(userId,"用戶" + userId); } }

2、測試

  一、建立第一個測試用例:github

    在類上添加@RunWith和@SpringBootTest表示是一個能夠啓動容器的測試類web

@RunWith(SpringRunner.class) @SpringBootTest //告訴SpringBoot去尋找主配置類(例如使用@SpringBootApplication註解標註的類),並使用它來啓動一個Spring application context;
public class UserController01Test { @Autowired private UserController userController; //測試@SpringBootTest是否會將@Component加載到Spring application context
 @Test public void testContexLoads(){ Assert.assertThat(userController,notNullValue()); } }

  二、Spring Test支持的一個很好的特性是應用程序上下文在測試之間緩存,所以若是在測試用例中有多個方法,或者具備相同配置的多個測試用例,它們只會產生啓動應用程序一次的成本。使用@DirtiesContext註解能夠清空緩存,讓程序從新加載。spring

  將上面代碼改造以下:在兩個方法上都添加@DirtiesContext註解,運行整個測試類,會發現容器加載了兩次。json

            

  三、啓動服務器對Controller進行測試:api

    這種方式是經過將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")); } }

  四、使用@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"))); } }

  五、使用@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); } }

 

 

資料:

  json-path : https://github.com/json-path/JsonPath

  mockito官網:https://site.mockito.org/

  spring官網用例:https://spring.io/guides/gs/testing-web/

  spring mockMvc文檔:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/web/servlet/MockMvc.html

相關文章
相關標籤/搜索