轉載註明出處:http://www.cnblogs.com/wade-xu/p/4311657.html html
The Spring MVC Test framework provides first class JUnit support for testing client and server-side Spring MVC code through a fluent API. Typically it loads the actual Spring configuration through theTestContext framework and always uses the
DispatcherServlet
to process requests thus approximating full integration tests without requiring a running Servlet container.web
Spring MVC 測試框架原本是一個獨立的項目,因爲發展的很好,早已合併到Spring Framework 3.2 裏了,測試框架提供了很好的API來測試客戶端和服務端的Spring MVC代碼, 本文以兩個例子講述了服務端的測試,閒話少說,讓咱們邊看例子邊學習。spring
目錄
Getting Ready
Example
Reference Class
Unit Test
Integration Testing
總結
Troubleshooting
參考
測試相關Maven dependency以下:json
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.0.3.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.9.5</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>spring-mvc
關於Spring項目的一些依賴如(spring-context, spring-web, spring-webmvc, spring-beans),這裏就不列舉了session
Controller 以下:mvc
@Controller @RequestMapping("/") public class DemoController { @Autowired private TestProjectService testProjectService; @RequestMapping(value = "jsonCompare", method = RequestMethod.POST) @ResponseBody public List<FieldComparisonFailure> jsonCompare(@RequestParam("expect") String expect, @RequestParam("actual") String actual, ModelMap model, HttpSession session) { List<FieldComparisonFailure> list = testProjectService.compare(expect, actual); return list; } }
FieldComparisonFailure類以下app
/** * Models a failure when comparing two fields. */ public class FieldComparisonFailure { private final String field; private final Object expected; private final Object actual; public FieldComparisonFailure(String field, Object expected, Object actual) { this.field = field; this.expected = expected; this.actual = actual; } public String getField() { return field; } public Object getExpected() { return expected; } public Object getActual() { return actual; } }
TestProjectService接口以下:框架
public interface TestProjectService { public List<FieldComparisonFailure> compare(String expect, String actual); }
TestProjectServiceImpl 具體實現是比較兩個Json字符串 返回一個Listwebapp
@Service public class TestProjectServiceImpl implements TestProjectService { @Override public List<FieldComparisonFailure> compare(String expect, String actual) { Comparator comparator = new Comparator(); List<FieldComparisonFailure> list = new ArrayList<FieldComparisonFailure>(); try { list = comparator.compare(expect, actual); } catch (JSONException e) { e.printStackTrace(); } return list; } }
##轉載註明出處:http://www.cnblogs.com/wade-xu/p/4311657.html
首先來看一個獨立的單元測試方式, 這個例子用Mockito 模擬service層以便隔離controller的測試。
package com.wadeshop.controller; import static org.mockito.Mockito.when; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.hamcrest.Matchers.hasSize; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import com.google.common.collect.ImmutableList; import com.wadeshop.service.TestProjectService; import com.wadeshop.entity.FieldComparisonFailure; public class DemoControllerTest_mock { @Mock private TestProjectService testProjectService; @InjectMocks private DemoController demoController; private MockMvc mockMvc; @Before public void setup() { // initialize mock object MockitoAnnotations.initMocks(this); // Setup Spring test in standalone mode this.mockMvc = MockMvcBuilders.standaloneSetup(demoController).build(); } @Test public void test() throws Exception { //prepare test data FieldComparisonFailure e1 = new FieldComparisonFailure("Number", "3", "4"); FieldComparisonFailure e2 = new FieldComparisonFailure("Number", "1", "2"); //actually parameter haven't use, service was mocked String expect = ""; String actual = ""; //Sets a return value to be returned when the method is called when(testProjectService.compare(expect, actual)).thenReturn(ImmutableList.of(e1, e2)); //construct http request and expect response this.mockMvc .perform(post("/jsonCompare") .accept(MediaType.APPLICATION_JSON) .param("actual", actual) .param("expect", expect)) .andDo(print()) //print request and response to Console .andExpect(status().isOk()) .andExpect(content().contentType("application/json;charset=UTF-8")) .andExpect(jsonPath("$", hasSize(2))) .andExpect(jsonPath("$[0].field").value("Number")) .andExpect(jsonPath("$[0].expected").value("3")) .andExpect(jsonPath("$[0].actual").value("4")) .andExpect(jsonPath("$[1].field").value("Number")) .andExpect(jsonPath("$[1].expected").value("1")) .andExpect(jsonPath("$[1].actual").value("2")); //verify Interactions with any mock verify(testProjectService, times(1)).compare(expect, actual); verifyNoMoreInteractions(testProjectService); } }
@Mock: 須要被Mock的對象
@InjectMocks: 須要將Mock對象注入的對象, 此處就是Controller
Before test
初始化Mock對象, 經過MockMvcBuilders.standaloneSetup模擬一個Mvc測試環境,注入controller, 經過build獲得一個MockMvc, 後面就用MockMvc的一些API作測試。
這不是真實的Spring MVC環境,若是要模擬真實環境須要用 MockMvcBuilders.webAppContextSetup(webApplicationContext).build(), 見下文。
測試方法裏面須要構建測試數據,mock service調用方法,返回一個ImmutableList (google-collections 谷歌的集合庫)
而後構造http請求而且傳入參數執行, 最後斷言驗證指望結果, 關於JsonPath的使用請參考http://goessner.net/articles/JsonPath/
運行
andDo(print()) 打印到控制檯的信息以下
MockHttpServletRequest: HTTP Method = POST Request URI = /jsonCompare Parameters = {actual=[], expect=[]} Headers = {Accept=[application/json]} Handler: Type = com.wadeshop.controller.DemoController Async: Was async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = null View = null Model = null FlashMap: MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Type=[application/json;charset=UTF-8]} Content type = application/json;charset=UTF-8 Body = [{"field":"Number","actual":"4","expected":"3"},{"field":"Number","actual":"2","expected":"1"}] Forwarded URL = null Redirected URL = null Cookies = []
##轉載註明出處:http://www.cnblogs.com/wade-xu/p/4311657.html
再來看集成Web環境方式, 此次仍然使用Spring MVC Test 但還須要加載 WebApplicationContext
import static org.hamcrest.Matchers.hasSize; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; 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.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration(value = "src/main/webapp") @ContextConfiguration("file:src/main/resources/applicationContext.xml") public class DemoControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setUp() { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void test() throws Exception { String actual = "{\"orderNumber\": \"4955\",\"orderVersion\": \"1\"}"; String expect = "{\"orderNumber\": \"4956\",\"orderVersion\": \"1\"}"; this.mockMvc .perform(post("/jsonCompare") .accept(MediaType.APPLICATION_JSON) .param("actual", actual) .param("expect", expect)) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType("application/json")) .andExpect(jsonPath("$", hasSize(1))) .andExpect(jsonPath("$[0].field").value("orderNumber")) .andExpect(jsonPath("$[0].actual").value("4955")) .andExpect(jsonPath("$[0].expected").value("4956")); } }
@RunWith: 告訴Junit使用 Spring-Test 框架, 容許加載web 應用程序上下文。
@WebAppConfiguration: 代表該類會使用web應用程序的默認根目錄來載入ApplicationContext, value = "src/main/webapp" 能夠不填,默認此目錄
@ContextConfiguration: 指定須要加載的spring配置文件的地址 ("file:src/main/resources/applicationContext.xml")
@Autowired WebApplicationContext wac:注入web環境的ApplicationContext容器;
使用MockMvcBuilders.webAppContextSetup(wac).build()來建立一個MockMvc進行測試, 此爲模擬真實的Spring MVC環境
測試過程和前面一個例子大致類似,惟一的區別就是,此次傳入的是真實的參數,調用真實的service取得返回值。
運行時間比較長
控制檯信息
MockHttpServletRequest: HTTP Method = POST Request URI = /jsonCompare Parameters = {actual=[{"orderNumber": "4955","orderVersion": "1"}], expect=[{"orderNumber": "4956","orderVersion": "1"}]} Headers = {Accept=[application/json]} Handler: Type = com.wadeshop.controller.DemoController Async: Was async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = null View = null Model = null FlashMap: MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Type=[application/json]} Content type = application/json Body = [{"field":"orderNumber","actual":"4955","expected":"4956"}] Forwarded URL = null Redirected URL = null Cookies = []
從上面的例子來看集成測試Spring MVC controller是否是也很簡單, 稍微配置一下就好了。
##轉載註明出處:http://www.cnblogs.com/wade-xu/p/4311657.html
單元測試過程無非就這三部曲:
若是發現一些NoClassDefFoundError, 估計依賴的jar版本太舊了。
import 哪些類不要弄錯了,有些須要static import, IDE工具不必定會提示導入
MVC測試框架更多的API請參考這篇博客:http://jinnianshilongnian.iteye.com/blog/2004660
感謝閱讀,若是您以爲本文的內容對您的學習有所幫助,您能夠點擊右下方的推薦按鈕,您的鼓勵是我創做的動力。