SpringMVC Mock測試實現原理及實現過程詳解
什麼是mock測試?
在測試過程中,對於某些不容易構成或者不容易獲取的物件,用一個虛擬的物件來建立以便測試的測試方法,就是Mock測試。
Servlet、Request、Response等Servlet API相關物件本來就是由Servlet容器(Tomcat)建立的。
這個虛擬的物件就是Mock物件。
Mock物件是真實物件在除錯期間的代替品。
為什麼使用Mock測試?
- 避免開發模組之間的耦合
- 輕量、簡單、靈活
MockMVC介紹
MockMvcBuilder
他是用來構造MockMVC的構造器
主要有兩個實現:StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分別對應之前的兩種測試方式。
我們直接使用靜態工廠MockMvcBuilders建立即可。
MockMvcBuilders
負責建立MockMvcBuilder物件
有兩種建立方式
1、standaloneSetup(Object... controllers)
2、webAppContextSetup(WebApplicationContext wac):指定WebApplicationContext,將會從該上下文獲取相應的控制器並得到相應的MockMvc
MockMvc
對於伺服器端的Spring MVC測試支援主入口點。
通過MockMvcBuilder構造
MockMvcBuilder由MockMvcBuilders的靜態方法去構造。
核心方法:perform(RequestBuilder requestBuilder)---->執行一個RequestBuilder請求,會自動執行SpringMvc的流程並對映到相應的控制器執行處理,該方法的返回值是一個ResultActions;
ResultActions
andExpect
新增ResultMatcher驗證規則,驗證控制器執行完成後結果是否正確。
andDo
新增ResultHandler結果處理器,比如除錯時列印結果到控制檯;
andReturn
最後返回相應的MvcResult;然後進行自定義驗證/進行下一步的非同步處理。
MockMvcRequestBuilders
- 用來構造請求
- 主要由兩個子類MockHttpServletRequestBuilder和MockMultipartHttpServletRequestBuilder(如檔案上傳),即用來Mock客戶端請求需要的所有資料。
MockMvcResultMatchers
- 用來匹配執行完請求後的結果驗證
- 如果匹配失敗將丟擲相應的異常
- 包含了很多驗證API方法
MockMvcResultHandlers
- 結果處理器,表示要對結果做點什麼事情
- 比如此處使用MockMvcResultHandlers.print()輸出整個相應結果資訊。
MvcResult
單元測試執行結果,可以針對執行結果進行自定義驗證邏輯。
MocMvc的使用
新增依賴
<!-- spring 單元測試元件包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.7.RELEASE</version> </dependency> <!-- 單元測試Junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
測試類
TestMockMVC.java
package com.cyb.ssm.controller.test; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; //@WebAppConfiguration:可以在單元測試的時候,不用啟動Servlet容器,就可以獲取一個Web應用上下文 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring/*.xml") @WebAppConfiguration public class TestMockMVC { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void Setup() { // 初始化一個MockMVC物件的方式有兩種:單獨設定、web應用上下文設定 // 建議使用web應用上下文設定 mockMvc = new MockMvcBuilders().webAppContextSetup(wac).build(); } @Test public void test() throws Exception { // 通過perform去執行一個Http請求 // andExpect:通過該方法,判斷請求執行是否成功 // andDo:對請求之後的結果,進行輸出 MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/item/showEdit").param("id","1")) .andExpect(MockMvcResultMatchers.view().name("item/item-edit")) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()) .andReturn(); System.out.println("==============="); System.out.println(result.getHandler()); } }
執行結果如下
JRE Oracle Corporation/13.0.1 is not supported,advanced source lookup disabled. 12月 12,2019 4:48:43 下午 org.springframework.test.context.support.AbstractTestContextBootstrapper getDefaultTestExecutionListenerClassNames 資訊: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener,org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener,org.springframework.test.context.support.DependencyInjectionTestExecutionListener,org.springframework.test.context.support.DirtiesContextTestExecutionListener,org.springframework.test.context.transaction.TransactionalTestExecutionListener,org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener] 12月 12,2019 4:48:43 下午 org.springframework.test.context.support.AbstractTestContextBootstrapper getTestExecutionListeners 資訊: Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@4470f8a6,org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@7c83dc97,org.springframework.test.context.support.DependencyInjectionTestExecutionListener@7748410a,org.springframework.test.context.support.DirtiesContextTestExecutionListener@740773a3,org.springframework.test.context.transaction.TransactionalTestExecutionListener@37f1104d,org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@55740540] 12月 12,2019 4:48:43 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 資訊: Loading XML bean definitions from file [D:\JAVA\eclipse_setup\ssm-project\target\classes\spring\applicationContext-dao.xml] 12月 12,2019 4:48:43 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 資訊: Loading XML bean definitions from file [D:\JAVA\eclipse_setup\ssm-project\target\classes\spring\applicationContext-service.xml] 12月 12,2019 4:48:43 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 資訊: Loading XML bean definitions from file [D:\JAVA\eclipse_setup\ssm-project\target\classes\spring\applicationContext-tx.xml] 12月 12,2019 4:48:43 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 資訊: Loading XML bean definitions from file [D:\JAVA\eclipse_setup\ssm-project\target\classes\spring\springmvc.xml] 12月 12,2019 4:48:43 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh 資訊: Refreshing org.springframework.web.context.support.GenericWebApplicationContext@50ad3bc1: startup date [Thu Dec 12 16:48:43 CST 2019]; root of context hierarchy 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/item/updateItem],produces=[application/json;charset=utf8]}" onto public com.cyb.ssm.po.Item com.cyb.ssm.controller.ItemController.updateItem(java.lang.Integer,java.lang.String,java.lang.Float,com.cyb.ssm.po.Item,org.springframework.web.multipart.MultipartFile) throws java.lang.Exception 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/item/testRedirect],produces=[application/json;charset=utf8]}" onto public java.lang.String com.cyb.ssm.controller.ItemController.testRedirect(javax.servlet.http.HttpServletRequest) 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/item/testForward],produces=[application/json;charset=utf8]}" onto public java.lang.String com.cyb.ssm.controller.ItemController.testForward(javax.servlet.http.HttpServletRequest) 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/item/findItem],produces=[application/json;charset=utf8]}" onto public java.lang.String com.cyb.ssm.controller.ItemController.findItem(java.lang.Integer) 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/item/queryItem],produces=[application/json;charset=utf8]}" onto public org.springframework.web.servlet.ModelAndView com.cyb.ssm.controller.ItemController.queryItem() throws com.cyb.ssm.exception.CustomException 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/item/queryItem2],produces=[application/json;charset=utf8]}" onto public com.cyb.ssm.po.Item com.cyb.ssm.controller.ItemController.queryItem2(com.cyb.ssm.po.ItemQueryVO) 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/item/deleteItem],produces=[application/json;charset=utf8]}" onto public void com.cyb.ssm.controller.ItemController.deleteItem(java.lang.String[]) 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/item/saveItem],produces=[application/json;charset=utf8]}" onto public java.util.Date com.cyb.ssm.controller.ItemController.saveItem(java.util.Date) 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/item/showEdit],produces=[application/json;charset=utf8]}" onto public org.springframework.web.servlet.ModelAndView com.cyb.ssm.controller.ItemController.showEdit(java.lang.Integer) 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/item/batchUpdateItem],produces=[application/json;charset=utf8]}" onto public java.util.List<com.cyb.ssm.po.Item> com.cyb.ssm.controller.ItemController.batchUpdateItem(com.cyb.ssm.po.ItemQueryVO) 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry register 資訊: Mapped "{[/queryItemByIdWithRest]}" onto public com.cyb.ssm.po.Item com.cyb.ssm.controller.RestItemController.queryItemById() 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter initControllerAdviceCache 資訊: Looking for @ControllerAdvice: org.springframework.web.context.support.GenericWebApplicationContext@50ad3bc1: startup date [Thu Dec 12 16:48:43 CST 2019]; root of context hierarchy 12月 12,2019 4:48:44 下午 org.springframework.mock.web.MockServletContext log 資訊: Initializing Spring FrameworkServlet '' 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.FrameworkServlet initServletBean 資訊: FrameworkServlet '': initialization started 12月 12,2019 4:48:44 下午 org.springframework.web.servlet.FrameworkServlet initServletBean 資訊: FrameworkServlet '': initialization completed in 17 ms com.cyb.ssm.po.Item@1ad9b8d3 MockHttpServletRequest: HTTP Method = GET Request URI = /item/showEdit Parameters = {id=[1]} Headers = {} Body = <no character encoding set> Session Attrs = {} Handler: Type = com.cyb.ssm.controller.ItemController Method = public org.springframework.web.servlet.ModelAndView com.cyb.ssm.controller.ItemController.showEdit(java.lang.Integer) Async: Async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = item/item-edit View = null Attribute = item value = com.cyb.ssm.po.Item@1ad9b8d3 errors = [] FlashMap: Attributes = null MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Language=[en]} Content type = null Body = Forwarded URL = /WEB-INF/jsp/item/item-edit.jsp Redirected URL = null Cookies = [] =============== public org.springframework.web.servlet.ModelAndView com.cyb.ssm.controller.ItemController.showEdit(java.lang.Integer)
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。