1、單元測試的目的前端
簡單來講就是在咱們增長或者改動一些代碼之後對全部邏輯的一個檢測,尤爲是在咱們後期修改後(不管是增長新功能,修改bug),均可以作到從新測試的工做。以減小咱們在發佈的時候出現更過甚至是出現以前解決了的問題再次重現。java
這裏主要是使用MockMvc對咱們的系統的Controller進行單元測試。web
對數據庫的操做使用事務實現回滾,及對數據庫的增刪改方法結束後將會還遠數據庫。spring
2、MockMvc的使用數據庫
一、首先咱們上一個例子,apache
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Before; 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.transaction.TransactionConfiguration; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.RequestBuilder; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 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.status; /** * Created by zhengcanrui on 16/8/11. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:spring/applicationContext-*xml"}) //配置事務的回滾,對數據庫的增刪改都會回滾,便於測試用例的循環利用 @TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true) @Transactional @WebAppConfiguration public class Test { //記得配置log4j.properties ,的命令行輸出水平是debug protected Log logger= LogFactory.getLog(TestBase.class); protected MockMvc mockMvc; @Autowired protected WebApplicationContext wac; @Before() //這個方法在每一個方法執行以前都會執行一遍 public void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); //初始化MockMvc對象 } @org.junit.Test public void getAllCategoryTest() throws Exception { String responseString = mockMvc.perform( get("/categories/getAllCategory") //請求的url,請求的方法是get .contentType(MediaType.APPLICATION_FORM_URLENCODED) //數據的格式 .param("pcode","root") //添加參數 ).andExpect(status().isOk()) //返回的狀態是200 .andDo(print()) //打印出請求和相應的內容 .andReturn().getResponse().getContentAsString(); //將相應的數據轉換爲字符串 System.out.println("--------返回的json = " + responseString); } }
Spring MVC的測試每每看似比較複雜。其實他的不一樣在於,他須要一個ServletContext來模擬咱們的請求和響應。可是Spring也針對Spring MVC 提供了請求和響應的模擬測試接口,以方便咱們的單元測試覆蓋面不僅是service,dao層。json
二、代碼解釋:spring-mvc
@webappconfiguration是一級註釋,用於聲明一個ApplicationContext集成測試加載WebApplicationContext。做用是模擬ServletContexttomcat
@ContextConfiguration:由於controller,component等都是使用註解,須要註解指定spring的配置文件,掃描相應的配置,將類初始化等。mvc
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true) @Transactional
上面兩句的做用是,讓咱們對數據庫的操做會事務回滾,如對數據庫的添加操做,在方法結束以後,會撤銷咱們對數據庫的操做。
爲何要事務回滾?
方法解析:
注意事項:
三、後臺的返回數據中,最好帶上咱們對數據庫的修改的結果返回的前端。
爲何要在data中返回一個修改或者添加的對象
咱們發送一個添加操做,添加一個SoftInfo對象,SoftInfo類定義以下:
public class SoftInfo { private String id; private String name; }
添加完以後,因爲咱們進行了單元測試的事務回滾,咱們將不能再數據庫中看咱們咱們的的添加操做,沒法判斷操做是否成功。
爲了解決上面的問題,咱們能夠在返回的json的數據中添加一個「data」字段,解析該json中的data字段數據,判斷咱們的添加操做是否成功的。json格式以下:
{ "status":200, "data":{"id":"2","name":"測試"} }
咱們可使用andExpect方法對返回的數據進行判斷,用「$.屬性」獲取裏面的數據,如我要獲取返回數據中的"data.name",能夠寫成"$.data.name"。下面的例子是判斷返回的data.name=「測試」。
@Test public void testCreateSeewoAccountUser() throws Exception { mockMvc.perform(post("/users") .contentType(MediaType.APPLICATION_FORM_URLENCODED) ).andExpect(status().isOk()) .andExpect(jsonPath("$.data.name", is("測試")))) .andExpect(jsonPath("$.data.createTime", notNullValue())) ; }
3、遇到的問題
一、發送一個被@ResponseBody標識的參數,一直到400錯誤。 即沒法發送一個json格式的數據到Controller層。
解決方法1:
SoftInfo softInfo = new SoftInfo();
//設置值
ObjectMapper mapper = new ObjectMapper(); ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter(); java.lang.String requestJson = ow.writeValueAsString(softInfo); String responseString = mockMvc.perform( post("/softs").contentType(MediaType.APPLICATION_JSON).content(requestJson)).andDo(print()) .andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
解決方法2:使用com.alibaba.fastjson.JSONObject將對象轉換爲Json數據
SoftInfo softInfo = new SoftInfo(); //。。。設置值 String requestJson = JSONObject.toJSONString(folderInfo); String responseString = mockMvc.perform( post("/softs").contentType(MediaType.APPLICATION_JSON).content(requestJson)).andDo(print()) .andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
注意上面contentType須要設置成MediaType.APPLICATION_JSON,即聲明是發送「application/json」格式的數據。使用content方法,將轉換的json數據放到request的body中。
二、java.lang.NoClassDefFoundError: com/jayway/jsonpath/InvalidPathException
缺乏了jar包:
能夠添加一下的maven依賴
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>0.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>0.8.1</version>
<scope>test</scope>
</dependency>
學習連接:https://www.petrikainulainen.net/spring-mvc-test-tutorial/
致謝:感謝您的閱讀!