SpringBoot使用MockMVC單元測試Controller


對模塊進行集成測試時,希望能夠通過輸入URL對Controller進行測試,如果通過啟動服務器,建立http client進行測試,這樣會使得測試變得很麻煩,比如,啟動速度慢,測試驗證不方便,依賴網絡環境等,這樣會導致測試無法進行,為了可以對Controller進行測試,可以通過引入MockMVC進行解決。

  MockMvc實現了對Http請求的模擬,能夠直接使用網絡的形式,轉換到Controller的調用,這樣可以使得測試速度快、不依賴網絡環境,而且提供了一套驗證的工具,這樣可以使得請求的驗證統一而且很方便。

       MockMvcBuilder是用來構造MockMvc的構造器,其主要有兩個實現:StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分別對應兩種測試方式,即獨立安裝和集成Web環境測試(此種方式並不會集成真正的web環境,而是通過相應的Mock API進行模擬測試,無須啟動服務器)。對於我們來說直接使用靜態工廠MockMvcBuilders創建即可。

下面就寫一個簡單的案例,告訴你是如何使用MockMvc進行Controller測試的

第一步、創建項目

創建一個Maven項目(springboot-junit),並配置pom.xml,參照下面代碼

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.lvgang</groupId> <artifactId>springboot-junit</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot-junit</name> <url>http://maven.apache.org</url> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies> </project> 

創建一個Controller類,我們在后面就測試空上Controller

package org.lvgang; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @RequestMapping("/") public String hello(String name){ return "hello "+name; } } 

第二步、編寫測試類

下面我們就是編寫測試類了

package org.lvgang; import org.junit.Assert; 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.MediaType; import org.springframework.test.context.junit4.SpringRunner; 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.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; //SpringBoot1.4版本之前用的是SpringJUnit4ClassRunner.class @RunWith(SpringRunner.class) //SpringBoot1.4版本之前用的是@SpringApplicationConfiguration(classes = Application.class) @SpringBootTest(classes = App.class) //測試環境使用,用來表示測試環境使用的ApplicationContext將是WebApplicationContext類型的 @WebAppConfiguration public class HelloControllerTest { @Autowired private WebApplicationContext webApplicationContext; private MockMvc mockMvc; @Before public void setUp() throws Exception{ //MockMvcBuilders.webAppContextSetup(WebApplicationContext context):指定WebApplicationContext,將會從該上下文獲取相應的控制器並得到相應的MockMvc; mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();//建議使用這種 } @Test public void getHello() 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= mockMvc.perform(MockMvcRequestBuilders.get("/") .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("hello lvgang",content); //斷言,判斷返回的值是否正確 } } 

整個測試過程如下:

1、准備測試環境

2、通過MockMvc執行請求

3、添加驗證斷言

4、添加結果處理器

5、得到MvcResult進行自定義斷言/進行下一步的異步請求

6、卸載測試環境

第三步、測試結果

通過執行HelloControllerTest,得到以下結果:

並且把整個返回結果都打印到了Console中

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /
       Parameters = {name=[lvgang]}
          Headers = {Accept=[text/html]}

Handler:
             Type = org.lvgang.HelloController
           Method = public java.lang.String org.lvgang.HelloController.hello(java.lang.String) Async: Async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = null View = null Model = null FlashMap: Attributes = null MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Type=[text/html;charset=UTF-8], Content-Length=[12]} Content type = text/html;charset=UTF-8 Body = hello lvgang Forwarded URL = null Redirected URL = null Cookies = []

通過以上代碼,我們就完成了一個簡單的案例。

附:

RequestBuilder/MockMvcRequestBuilders

在上面的測試類中,我們用到了這么一個類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; 

MockMvcRequestBuilders通過方法得到兩類Builder,一個是MockHttpServletRequestBuilder ,一個是MockMultipartHttpServletRequestBuilder (上傳文件)

MockHttpServletRequestBuilder:

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 param(String name,String... values):請求傳入參數 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):請求的后處理器,用於自定義一些請求處理的擴展點; 

MockMultipartHttpServletRequestBuilder:

MockMultipartHttpServletRequestBuilder繼承自MockHttpServletRequestBuilder,又提供了如下API:

MockMultipartHttpServletRequestBuilder file(String name, byte[] content)/MockMultipartHttpServletRequestBuilder file(MockMultipartFile file):指定要上傳的文件;

ResultActions

調用MockMvc.perform(RequestBuilder requestBuilder)后將得到ResultActions,通過ResultActions完成如下三件事:

ResultActions andExpect(ResultMatcher matcher) :添加驗證斷言來判斷執行請求后的結果是否是預期的;
ResultActions andDo(ResultHandler handler) :添加結果處理器,用於對驗證成功后執行的動作,如輸出下請求/結果信息用於調試; MvcResult andReturn() :返回驗證成功后的MvcResult;用於自定義驗證/下一步的異步處理;

ResultMatcher/MockMvcResultMatchers

ResultMatcher用來匹配執行完請求后的結果驗證,其就一個match(MvcResult result)斷言方法,如果匹配失敗將拋出相應的異常;此類案例中並為使用,請自行查看。具體提供以下API:

HandlerResultMatchers handler():請求的Handler驗證器,比如驗證處理器類型/方法名;此處的Handler其實就是處理請求的控制器; RequestResultMatchers request():得到RequestResultMatchers驗證器; ModelResultMatchers model():得到模型驗證器; ViewResultMatchers view():得到視圖驗證器; FlashAttributeResultMatchers flash():得到Flash屬性驗證; StatusResultMatchers status():得到響應狀態驗證器; HeaderResultMatchers header():得到響應Header驗證器; CookieResultMatchers cookie():得到響應Cookie驗證器; ContentResultMatchers content():得到響應內容驗證器; JsonPathResultMatchers jsonPath(String expression, Object ... args)/ResultMatcher jsonPath(String expression, Matcher matcher):得到Json表達式驗證器; XpathResultMatchers xpath(String expression, Object... args)/XpathResultMatchers xpath(String expression, Map<string, string=""> namespaces, Object... args):得到Xpath表達式驗證器; ResultMatcher forwardedUrl(final String expectedUrl):驗證處理完請求后轉發的url(絕對匹配); ResultMatcher forwardedUrlPattern(final String urlPattern):驗證處理完請求后轉發的url(Ant風格模式匹配,@since spring4); ResultMatcher redirectedUrl(final String expectedUrl):驗證處理完請求后重定向的url(絕對匹配);

ResultMatcher redirectedUrlPattern(final String expectedUrl):驗證處理完請求后重定向的url(Ant風格模式匹配,@since spring4);


https://my.oschina.net/sdlvzg/blog/1594821


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM