## maven依賴
spring-boot-starter-test包含引入了JUnit。
```
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
```
## 注解介紹
* @RunWith(SpringRunner.class):指定JUnit使用Spring環境運行。SpringRunner 繼承了SpringJUnit4ClassRunner,沒有擴展任何功能,使用前者,名字簡短而已。
* @SpringBootTest:會模擬SpringBoot應用啟動,尋找帶有SpringBootApplication的配置類啟動,創建ApplicationContext容器。
* classes:此屬性指定Spring Boot工程的啟動類
* webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,指定一個隨機端口,去啟動內置的web應用服務器
* @WebMvcTest:只實例化Controller層,如果Controller層對Service層中有依賴關系,可以使用@MockBean注解進行模擬
* @LocalServerPort:該注解會把springboot內置web應用服務器啟動端口賦給其注解的字段。
* @TestConfiguration:用它我們可以在一般的@Configuration之外補充測試專門用的Bean或者自定義的配置。
* @TestComponent:是另一種@Component,在語義上用來指定某個Bean是專門用于測試的。
* @MockBean:模擬Spring環境,解決測試中依賴問題,以下`@WebMvcTest使用`中即是@MockBean的經典使用
## @SpringBootTest使用
```
@RunWith(SpringRunner.class)
@SpringBootTest(classes = StartUpApplication.class,webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloControllerTest {
@LocalServerPort
private int port;
private String baseUrl;
@Autowired
private TestRestTemplate restTemplate;
@BeforeEach
public void setUp(){
this.baseUrl="http://127.0.0.1:"+port;
}
@Test
public void index() {
System.out.println("request url is: "+baseUrl);
ResponseEntity<String> response = restTemplate.getForEntity(baseUrl, String.class);
System.out.println(response.getBody());
Assertions.assertEquals(response.getBody(),"Welcome to Spring Boot!");
}
}
```
## MockMvc詳解
* 上面介紹的@SpringBootTest測試適合Service和DAO層方法的測試,不需要創建MockMvc
* 對Controller的方法進行測試,需要模擬HTTP環境,如果啟動服務器,效率很低,Spring引入了MockMVC,實現了對Http請求的模擬,能夠直接使用網絡的形式,轉換到Controller的調用
* 注解:@AutoConfigureMockMvc,相當于new MockMvc
* 工具類:MockMvc(3步)
* perform:執行一個RequestBuilder請求,會自動執行SpringMVC的流程并映射到相應的控制器執行處理;
* MockMvcRequestBuilders提供了get/post/put/delete/upload等http請求的方式
* 提供了header/contentType/cookie/characterEncoding/params等設置request參數的方式
* ResultActions
* andExpect:添加ResultMatcher驗證規則,驗證控制器執行完成后結果是否正確;
* andDo:添加ResultHandler結果處理器,比如調試時打印結果到控制臺;
* andReturn:最后返回相應的MvcResult;然后進行自定義驗證/進行下一步的異步處理;
* MvcResult(自定義Assert)
* getModelAndView:獲得控制層設置的ModeAndView對象
* getResponse:獲得最終響應結果
```
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testHello() throws Exception {
/*
* 1、mockMvc.perform執行一個請求。
* 2、MockMvcRequestBuilders.get("XXX")構造一個請求。
* 3、ResultActions.param添加請求傳值
* 4、ResultActions.accept(MediaType.TEXT_HTML_VALUE))設置返回類型
* 5、ResultActions.andExpect添加執行完成后的斷言。
* 6、ResultActions.andDo添加一個結果處理器,表示要對結果做點什么事情
* 比如此處使用MockMvcResultHandlers.print()輸出整個響應結果信息。
* 7、ResultActions.andReturn表示執行完成后返回相應的結果,返回MvcResult。
*/
MvcResult result = mockMvc.perform(MockMvcRequestBuilders
.get("/hello")
// 設置返回值類型為utf-8,否則默認為ISO-8859-1
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE)
.param("name", "Tom"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("Hello Tom!"))
.andDo(MockMvcResultHandlers.print()).andReturn();
Assert.assertNotNull(result.getModelAndView().getModel().get("user"));
}
}
```
## @WebMvcTest使用
```
@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
//模擬出一個userService
@MockBean
private UserService userService;
@Test
public void testService() 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);
}
}
```