--- title: Spring Test Mode". --- https://www.jianshu.com/p/e65226050463 ![](https://i.imgur.com/NAZG7r0.png) # API單元測試-JUnt4 ## 1.創建test 建立路徑 /src/test/java 以及 /src/test/resources,將撰寫的單元測試放在 /src/test/java,resources 下則放希望在測試環境下套用的資源檔 ![Uploading file..._b3daxgn8w]() ### pom.xml中要添加依賴 ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> ``` --- ### 1)在需要創建單元測試的controller上右鍵選——>go to——>test ![](https://i.imgur.com/uwqW4U8.png) ### 2)選create New Test.... ![](https://i.imgur.com/xLWgSjk.png) ### 3)選擇需要單元測試的方法 ![](https://i.imgur.com/pl0ATNp.png) ### 4)創建完成 ![](https://i.imgur.com/TT0riqb.png) --- ## 2.測試方法,如下 參考hungry ### MockMvc(模擬真實API) ![](https://i.imgur.com/HZsDLIq.png) ### 1)登入測試 ```typescript import com.fasterxml.jackson.databind.ObjectMapper; import com.tgfc.tw.MainApplication; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpSession; import org.springframework.test.annotation.Rollback; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; import javax.servlet.http.Cookie; import java.util.*; @RunWith(SpringRunner.class)//RunWith就是一个運行器,定義測試程式要在Spring Boot的環境下運行 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = MainApplication.class) //webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT啟動內置的容器,執行中會隨機生成一個port @AutoConfigureMockMvc//代表測試時會在元件容器中建立MockMvc元件 public class UserControllerTest { //資料格式轉換,轉成json字符串 private ObjectMapper objectMapper = new ObjectMapper(); @Autowired private MockMvc mockMvc;//放登入後回傳的資料 MockHttpSession session; //新增一個cookies陣列 Cookie[] cookies; String xsrf; @Autowired WebApplicationContext webApplicationContext; //執行任何方法前都會先執行init() @Before public void init() throws Exception { //新增一個Map來放jasn格式的資料 Map<String, String> param = new HashMap<>(); param.put("account", "admin"); param.put("password", "123456"); //設呼叫路徑、HTTP METHOD(方法)、contentType(傳遞型態)、content(上傳資料) MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/api/login") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(param)); //執行 requestBuilder MvcResult Resultu=mockMvc.perform(requestBuilder).andReturn(); //取cookies的值 cookies=Resultu.getResponse().getCookies(); //取session的值 session=(MockHttpSession)Resultu.getRequest().getSession(); //找出XSRF-TOKEN for(Cookie cookie:cookies){ if(cookie.getName().equals("XSRF-TOKEN")){ xsrf= cookie.getValue(); } } } ``` ### 2) 傳址方式傳遞引數 ```typescript //測試 @Test //Rollback需要加上Transactional @Transactional //測完後還原 @Rollback public void get() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/api/user/get") .session(session) .param("id", "1")//傳值(Parameters),以傳址方式傳遞引數 .accept(MediaType.APPLICATION_JSON))//回傳格式 .andExpect(MockMvcResultMatchers.status().isOk())//驗證狀態是否200 .andDo(MockMvcResultHandlers.print());//印出 } ``` ### 3) body傳值(Map接值) ```typescript @Test @Transactional @Rollback public void update() throws Exception { Map<String, Object> param = new HashMap<>(); List<Integer> list=new ArrayList<>(); list.add(1); param.put("id", 6); param.put("name", "Amy2"); param.put("englishName", "Amy2"); param.put("floorId", 2); param.put("permissions",list); //呼叫路徑、HTTP METHOD(方法)、contentType(傳遞型態)、content(上傳資料)、 //設定cookie、設定header mockMvc.perform(MockMvcRequestBuilders.put("/api/user/update")//新Post,刪Delete,修Put,查Get .contentType(MediaType.APPLICATION_JSON_VALUE)//傳入json格式 .cookie(new Cookie("XSRF-TOKEN",xsrf)) .header("X-XSRF-TOKEN",xsrf) .session(session) .content(objectMapper.writeValueAsString(param))//json格式方法傳值 .accept(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()); } ``` ### 4) body傳值(JSONObject接值) ```typescript @Test @Transactional @Rollback public void update() throws Exception { JSONObject request = new JSONObject(); request.put("id", 6); request.put("name", "Amy2"); request.put("englishName", "Amy2"); request.put("floorId", 2); request.put("permissions",list); mockMvc.perform(MockMvcRequestBuilders.put("/api/user/update") .contentType(MediaType.APPLICATION_JSON_VALUE) .cookie(new Cookie("XSRF-TOKEN",xsrf)) .header("X-XSRF-TOKEN",xsrf) .session(session) .content(request.toString()) .accept(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()); } ``` ### 5) file傳值 ```typescript //file測試,無法使用@Rollback @Test public void uploadPhoto() throws Exception{ InputStream inputStream = new FileInputStream(new File("../hungry/src/test/resource/mc2.jpg")); //File转MockMultipartFile MockMultipartFile multipartFile = new MockMultipartFile("files", "1528095526.jpg", null, inputStream); mockMvc.perform(MockMvcRequestBuilders .multipart("/api/upload/photo") .file(multipartFile)//file傳值 .contentType(MediaType.IMAGE_JPEG)//圖片格式上傳 .cookie(new Cookie("XSRF-TOKEN",xsrf)) .header("X-XSRF-TOKEN",xsrf) .session(session) .accept(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()); } @Test public void getPhoto() throws Exception{ mockMvc.perform(MockMvcRequestBuilders.get("/api/images/{fileName}","1574668907557.jpg") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .param("fileName", "1574668907557.jpg") .cookie(new Cookie("XSRF-TOKEN",xsrf)) .header("X-XSRF-TOKEN",xsrf) .session(session) .accept(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()); } } ``` --- ## 4.回傳資料 andDo(MockMvcResultHandlers.print())印出的測試資訊 ```typescript MockHttpServletRequest://Request的資料 HTTP Method = GET Request URI = /api/orderHistory/getGroupByOrder Parameters = {groupId=[339], storeId=[241], floorId=[1]} Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json", X-XSRF-TOKEN:"cd71e913-dde7-440a-bb10-ca2b39bda4de", Cookie:"XSRF-TOKEN=cd71e913-dde7-440a-bb10-ca2b39bda4de"] Body = null Session Attrs = {SPRING_SECURITY_CONTEXT=org.springframework.security.core.context.SecurityContextImpl@fcf2e3eb: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@fcf2e3eb: Principal: com.tgfc.tw.entity.model.response.user.UserResponse@497f8a4b; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_SUPER_MANAGER, ROLE_MANAGER} Handler: Type = com.tgfc.tw.controller.OrderHistoryController Method = public java.util.List<com.tgfc.tw.entity.model.response.orderHistory.OrderHistoryCountOrderResponse> com.tgfc.tw.controller.OrderHistoryController.getGroupByOrder(int,int,java.lang.Integer) MockHttpServletResponse://Response的回傳資料 Status = 200 Error message = null Headers = [Set-Cookie:"XSRF-TOKEN=5c26d23d-51d0-4d40-991f-591ae4c86434; Path=/; HttpOnly", Content-Type:"application/json;charset=UTF-8", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"SAMEORIGIN"] Content type = application/json;charset=UTF-8 Body = [{"store":{"id":241,"storeName":"新增店家part2","storeTel":"04222655441","storeAddress":"","remark":"","tag":[],"pictures":[{"id":853,"storePictureUrl":"/api/images/1574651380569.jpg","storePicName":"1574651380569.jpg"}]},"countByOrder":[{"id":269,"name":"1便當","price":60,"count":2,"totalPrice":120,"content":[{"id":128,"name":"無","price":0,"count":2,"totalPrice":0,"orderPrice":0,"user":null}]}]}] Forwarded URL = null Redirected URL = null Cookies = [[Cookie@5a5c041f name = 'XSRF-TOKEN', value = '5c26d23d-51d0-4d40-991f-591ae4c86434', comment = [null], domain = [null], maxAge = -1, path = '/', secure = false, version = 0, httpOnly = true]] ``` # H2資料庫 ```xml= //設定資料庫 spring.datasource.driver-class-name=org.h2.Driver 設定testdb資料庫 spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.username=sa spring.datasource.password=sa ``` ## 創建資料表 1. 注意檔案有些語法和Mysql不同 2. exists:資料表不存在時創建 3. 注意名稱不可以改變 ![](https://i.imgur.com/ObqFMQr.png) ## 新增資料 1. 注意檔案檔案名稱不可以改變 ![](https://i.imgur.com/ADiZs0e.png) # API單元測試-JUnt5 進用JUnt4 ![](https://i.imgur.com/47bo7Jz.png)