前言
文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/bin392328206/six-finger
種一棵樹最好的時間是十年前,其次是現在
我知道很多人不玩qq了,但是懷舊一下,歡迎加入六脈神劍Java菜鳥學習羣,羣聊號碼:549684836 鼓勵大家在技術的路上寫博客
絮叨
最近再維護一個前人寫的系統,然後就發現了一個很大的問題,就是單元測試沒有寫,真的是心態崩潰,很多時候自己都不敢去改代碼,因爲怕一改代碼導致測試不到位,改多了bug,優化都不敢優化,只能說出現bug了,纔不得不改他的時候去改改。對於一個好的產品,六六覺得代碼的規範,可測試性,可拓展性,容錯性真的很重要。到後期的優化,重構全靠一期 二期的基礎,這些纔是一個產品能長久不衰的本質,但是目前大部分產品就是先活下來,然後再考慮這個問題,確實也是,因爲你活不下來,設計那麼好,又有啥用呢?但是作爲我們開發人員,可以自己多注意這些規範,說實話包括自己,以前碰到單元測試,我也不喜歡寫,因爲也許這個代碼一期是你開發的,後面都不一定是你去接手了,不過小六六得改掉這個習慣,以後自己的接口,儘量寫單元測試,算是立個flag吧。既然我用postMan,我爲啥不用mockMvc,我想缺點可能是每次的啓動時間有點長,如果項目很趕,可以放下,閒下來了,肯定得補的
使用junit測試業務層代碼
上面是一個分佈式頭條練習項目,我們可以看到他是一個標準的分佈式項目目錄結構,
然後我們找到我們要測試的service 然後 我們右鍵點擊他
然後你就可以直接創建你的測試類了
記得填好你下面的2個註解,你就可以愉快的做單元測試了。
使用mockmvc測試控制層代碼
爲何使用MockMvc
MockMvc實現了對Http請求的模擬,能夠直接使用網絡的形式,轉換到Controller的調用,這樣可以
使得測試速度快、不依賴網絡環境,而且提供了一套驗證的工具,這樣可以使得請求的驗證統一而
且很方便。
測試邏輯
- MockMvcBuilder構造MockMvc的構造器
- mockMvc調用perform,執行一個RequestBuilder請求,調用controller的業務處理邏輯
- perform返回ResultActions,返回操作結果,通過ResultActions,提供了統一的驗證方式
- 使用StatusResultMatchers對請求結果進行驗證
- 使用ContentResultMatchers對請求返回的內容進行驗證
具體代碼
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JunitApplication.class)
@WebAppConfiguration
public class JunitTestControllerTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mvc;
@Before
public void setUp()throws Exception {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void helloJunit() 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()輸出整個響應結果信息。
* 5、ResultActions.andReturn表示執行完成後返回相應的結果。
*/
MvcResult mvcResult= mvc.perform(MockMvcRequestBuilders.get("/junit/helloJunit")
// 參數傳遞
.param("name","lvgang")
.accept(MediaType.TEXT_HTML_VALUE))
// .andExpect(MockMvcResultMatchers.status().isOk()) //等同於Assert.assertEquals(200,status);
// .andExpect(MockMvcResultMatchers.content().string("hello lvgang")) //等同於 Assert.assertEquals("hello lvgang",content);
.andDo(MockMvcResultHandlers.print())
.andReturn();
int status=mvcResult.getResponse().getStatus(); //得到返回代碼
String content=mvcResult.getResponse().getContentAsString(); //得到返回結果
Assert.assertEquals(200,status); //斷言,判斷返回代碼是否正確
Assert.assertEquals("你好:Frank",content); //斷言,判斷返回的值是否正確
}
}
方法解析
- **perform:**執行一個RequestBuilder請求,會自動執行SpringMVC的流程並映射到相應的控制器執行處理;
- **get:**聲明發送一個get請求的方法。MockHttpServletRequestBuilder get(String urlTemplate, **Object…
- urlVariables):**根據uri模板和uri變量值得到一個GET請求方式的。另外提供了其他的請求的方法,如:post、put、delete等。
- **param:**添加request的參數,如上面發送請求的時候帶上了了pcode = - root的參數。假如使用需要發送json數據格式的時將不能使用這種方式,可見後面被@ResponseBody註解參數的解決方法
- **andExpect:**添加ResultMatcher驗證規則,驗證控制器執行完成後結果是否正確(對返回的數據進行的判斷);
- **andDo:**添加ResultHandler結果處理器,比如調試時打印結果到控制檯(對返回的數據進行的判斷);
- **andReturn:**最後返回相應的MvcResult;然後進行自定義驗證/進行下一步的異步處理(對返回的數據進行的判斷)。
MockMvcRequestBuilders常用API:
-
MockHttpServletRequestBuilder get(String urlTemplate, Object… - urlVariables):根據uri模板和uri變量值得到一個GET請求方式的MockHttpServletRequestBuilder;如get(/user/{id}, 1L);
-
MockHttpServletRequestBuilder post(String urlTemplate, Object… urlVariables):同get類似,但是是POST方法;
-
MockHttpServletRequestBuilder put(String urlTemplate, Object… urlVariables):同get類似,但是是PUT方法;
-
MockHttpServletRequestBuilder delete(String urlTemplate, Object… urlVariables) :同get類似,但是是DELETE方法;
-
MockHttpServletRequestBuilder options(String urlTemplate, Object… urlVariables):同get類似,但是是OPTIONS方法;
-
MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object… urlVariables): - 提供自己的Http請求方法及uri模板和uri變量,如上API都是委託給這個API;
-
MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object… - urlVariables):提供文件上傳方式的請求,得到MockMultipartHttpServletRequestBuilder;
-
RequestBuilder asyncDispatch(final MvcResult - mvcResult):創建一個從啓動異步處理的請求的MvcResult進行異步分派的RequestBuilder;
MockHttpServletRequestBuilder常用API:
-
MockHttpServletRequestBuilder header(String name, Object… values)/MockHttpServletRequestBuilder - headers(HttpHeaders httpHeaders):添加頭信息;
-
MockHttpServletRequestBuilder contentType(MediaType mediaType):指定請求的contentType頭信息;
-
MockHttpServletRequestBuilder accept(MediaType… mediaTypes)/MockHttpServletRequestBuilder accept(String… - mediaTypes):指定請求的Accept頭信息;
-
MockHttpServletRequestBuilder content(byte[] content)/MockHttpServletRequestBuilder content(String - content):指定請求Body體內容;
-
MockHttpServletRequestBuilder cookie(Cookie… cookies):指定請求的Cookie;
-
MockHttpServletRequestBuilder locale(Locale locale):指定請求的Locale;
-
MockHttpServletRequestBuilder characterEncoding(String encoding):指定請求字符編碼;
-
MockHttpServletRequestBuilder requestAttr(String name, Object value) :設置請求屬性數據;
-
MockHttpServletRequestBuilder sessionAttr(String name, Object value)/MockHttpServletRequestBuilder - sessionAttrs(Map<string, object=""> sessionAttributes):設置請求session屬性數據;
-
MockHttpServletRequestBuilder flashAttr(String name, Object value)/MockHttpServletRequestBuilder - flashAttrs(Map<string, object=""> flashAttributes):指定請求的flash信息,比如重定向後的屬性信息;
-
MockHttpServletRequestBuilder session(MockHttpSession session) :指定請求的Session;
-
MockHttpServletRequestBuilder principal(Principal principal) :指定請求的Principal;
-
MockHttpServletRequestBuilder contextPath(String contextPath) - :指定請求的上下文路徑,必須以“/”開頭,且不能以“/”結尾;
-
MockHttpServletRequestBuilder pathInfo(String pathInfo) :請求的路徑信息,必須以“/”開頭;
-
MockHttpServletRequestBuilder secure(boolean secure):請求是否使用安全通道;
-
MockHttpServletRequestBuilder with(RequestPostProcessor - postProcessor):請求的後處理器,用於自定義一些請求處理的擴展點;
MvcResult
-
MvcResult爲執行完控制器後得到的整個結果,並不僅僅是返回值,其包含了測試時需要的所有信息。
-
MockHttpServletRequest getRequest():得到執行的請求;
-
MockHttpServletResponse getResponse():得到執行後的響應;
-
Object getHandler():得到執行的處理器,一般就是控制器;
-
HandlerInterceptor[] getInterceptors():得到對處理器進行攔截的攔截器;
-
ModelAndView getModelAndView():得到執行後的ModelAndView;
-
Exception getResolvedException():得到HandlerExceptionResolver解析後的異常;
-
FlashMap getFlashMap():得到FlashMap;
-
Object getAsyncResult()/Object getAsyncResult(long timeout):得到異步執行的結果;
結尾
雖然說現在的業務千變萬化,但是如果有時間還是多寫寫單元測試吧。更多的實戰還是要碰到了纔會更瞭解。
日常求贊
好了各位,以上就是這篇文章的全部內容了,能看到這裏的人呀,都是真粉。
創作不易,各位的支持和認可,就是我創作的最大動力,我們下篇文章見
六脈神劍 | 文 【原創】如果本篇博客有任何錯誤,請批評指教,不勝感激 !
上面提到了 分佈式頭條項目 回覆 888 獲取 我敢說超過了大部分仔目前的技術範圍維度。