1. 程式人生 > >SpringBoot單元測試(二)MockMVC

SpringBoot單元測試(二)MockMVC

介紹

MockMvc,從字面來理解,很好理解,主要是用來模擬MVC。簡單來說,就是模擬可以從客戶端請求後端的Controller類。

樣例:

1. 非自動注入式

TestApplicationTests類已經有@RunWith(SpringRunner.class)和@SpringBootTest註解了,具體參考上一篇文章

SpringBoot 單元測試(一)SpringBootTest

package com.orjrs.spring.test.unit;

import com.orjrs.spring.test.TestApplicationTests;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
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;

/**
 * MockMvcTest
 *
 * @author orjrs
 * @date 2018-10-06 20:15
 */
@WebAppConfiguration // 1
public class MockMvcTest extends TestApplicationTests {
    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

    @Before // @Test註解的方法執行前執行,MockMvcBuilder構造MockMvc例項
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

    @Test
    public void post() throws Exception {
        String name = "Smart LIU";
        String msg = "您好";
        mockMvc.perform(
                MockMvcRequestBuilders.post("/unit/sayHello/" + name + "/" + msg)
                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                //.content()
        )
                .andExpect(MockMvcResultMatchers.status().isOk())
                //.andExpect(MockMvcResultMatchers.content().contentType("text/plain;charset=UTF-8"))
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
    }
}

2. 自動注入
package com.orjrs.spring.test.unit;

import com.orjrs.spring.test.TestApplicationTests;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.http.MediaType;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
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;

/**
 * MockMvcTest
 *
 * @author orjrs
 * @date 2018-10-21 16:12
 */
@WebAppConfiguration // 1
@AutoConfigureMockMvc // 開啟MockMvc自動註解
public class AutoMockMvcTest extends TestApplicationTests {
    // @Autowired
    // private WebApplicationContext webApplicationContext;

    @Autowired
    private MockMvc mockMvc;

    /*@Before // @Test註解的方法執行前執行,MockMvcBuilder構造MockMvc例項
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }*/

    @Test
    public void post() throws Exception {
        String name = "Smart LIU";
        String msg = "您好";
        mockMvc.perform(
                MockMvcRequestBuilders.post("/unit/sayHello/" + name + "/" + msg)
                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                //.content()
        )
                .andExpect(MockMvcResultMatchers.status().isOk())
                //.andExpect(MockMvcResultMatchers.content().contentType("text/plain;charset=UTF-8"))
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
    }
}

原始碼分析:

MockMvcBuilders: 主要是用來構造MockMvc的。它有兩個方法,如下:

public class MockMvcBuilders {
    public MockMvcBuilders() {
    }
    // 通過指定WebApplicationContext,根據上下文獲取相應的Controller來構建MockMvc
    public static DefaultMockMvcBuilder webAppContextSetup(WebApplicationContext context) {
        return new DefaultMockMvcBuilder(context);
    }
    // 通過引數直接指定一組控制器來構建MockMVC
    public static StandaloneMockMvcBuilder standaloneSetup(Object... controllers) {
        return new StandaloneMockMvcBuilder(controllers);
    }
}

AbstractMockMvcBuilder還實現了ConfigurableMockMvcBuilder介面,即有以下方法

package org.springframework.test.web.servlet.setup;

import javax.servlet.Filter;
import org.springframework.test.web.servlet.MockMvcBuilder;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.ResultHandler;
import org.springframework.test.web.servlet.ResultMatcher;

public interface ConfigurableMockMvcBuilder<B extends ConfigurableMockMvcBuilder<B>> extends MockMvcBuilder {
    <T extends B> T addFilters(Filter... var1);// 新增過濾器

    <T extends B> T addFilter(Filter var1, String... var2);// 新增過濾器

    <T extends B> T defaultRequest(RequestBuilder var1);//預設的RequestBuilder,每次執行時會合併到自定義的RequestBuilder中,即提供公共請求資料的;

    <T extends B> T alwaysExpect(ResultMatcher var1); // 定義全域性的結果驗證器,即每次執行請求時都進行驗證的規則;

    <T extends B> T alwaysDo(ResultHandler var1);// 定義全域性結果處理器,即每次請求時都進行結果處理;

    <T extends B> T dispatchOptions(boolean var1); // DispatcherServlet是否分發OPTIONS請求方法到控制器;

    <T extends B> T apply(MockMvcConfigurer var1);
}
public interface MockMvcBuilder {
    MockMvc build();
}

StandaloneMockMvcBuilder除了繼承AbstractMockMvcBuilder之外,自己還提供了許多方法,這裡不多說了。

MockMvc:
mockMvc.perform(
                MockMvcRequestBuilders.post("/unit/sayHello/" + name + "/" + msg)
                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                //.content()
        )
                .andExpect(MockMvcResultMatchers.status().isOk())
                //.andExpect(MockMvcResultMatchers.content().contentType("text/plain;charset=UTF-8"))
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
    }

perform:執行一個RequestBuilder請求,會自動執行SpringMVC的流程並對映到相應的控制器執行處理,返回ResultActions類;

andExpect:新增ResultMatcher驗證規則,驗證控制器執行完成後結果是否正確;

andDo:新增ResultHandler結果處理器,比如除錯時列印結果到控制檯;

andReturn:最後返回相應的MvcResult;然後進行自定義驗證/進行下一步的非同步處理;

另外還提供了以下API:

setDefaultRequest:設定預設的RequestBuilder,用於在每次perform執行相應的RequestBuilder時自動把該預設的RequestBuilder合併到perform的RequestBuilder中;

setGlobalResultMatchers:設定全域性的預期結果驗證規則,如我們通過MockMvc測試多個控制器時,假設它們都想驗證某個規則時,就可以使用這個;

setGlobalResultHandlers:設定全域性的ResultHandler結果處理器;

RequestBuilder/MockMvcRequestBuilders

Request請求,有put、get、post、delete、patch、options、head、request、multipart、fileUpload、asyncDispatch請求方法。

MockHttpServletRequestBuilder和MockMultipartHttpServletRequestBuilder

主要是針對請求頭的。有header、contentType、cookie、characterEncoding、requestAttr、sessionAttr、contextPath等方法