微服務單元測試 Mock使用與詳解

最近在搞微服務的項目,搞完後發現內部須要調用別的服務的接口,但是另外一個服務尚未寫完我還調不通,哪這就很是尷尬了。這種狀況下要怎麼測試呢?這時就須要引入Mock的概念。前端

1 什麼是Mock

mock是在測試過程當中,對於一些不容易構造/獲取的對象,建立一個mock對象來模擬對象的行爲。好比說你須要調用B服務,但是B服務尚未開發完成,那麼你就能夠將調用B服務的那部分給Mock掉,並編寫你想要的返回結果。java

2 Spring Boot的測試類庫

如今絕大多數的java服務都是Spring框架搭建的,而且也會使用到Spring boot來進行快速搭建開發,在Spring Boot提供了許多實用工具和註解來幫助測試應用程序,主要包括如下兩個模塊:web

  • spring-boot-test:支持測試的核心內容。
  • spring-boot-test-autoconfigure:支持測試的自動化配置。

開發進行只要使用 spring-boot-starter-test 啓動器就能引入這些 Spring Boot 測試模塊,還能引入一些像 JUnit, AssertJ, Hamcrest 及其餘一些有用的類庫,具體以下所示:spring

  • JUnit:Java 應用程序單元測試標準類庫。
  • Spring Test & Spring Boot Test:Spring Boot 應用程序功能集成化測試支持。
  • AssertJ:一個輕量級的斷言類庫。
  • Mockito:一個Java Mock測試框架,默認支付 1.x,能夠修改成 2.x。
  • JsonPath:一個JSON操做類庫。

3 編寫測試用例

1 引入pom依賴

再IDEA中建立一個普通的maven項目便可,而後導入pom依賴:json

<parent>
        <groupId> org.springframework.boot </groupId>
        <artifactId> spring-boot-starter-parent </artifactId>
        <version>2.1.7.RELEASE </version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>
    </dependencies>
複製代碼

3.2 MockMVC基於RESTful風格的測試

對於先後端分離的項目而言,沒法直接從前端靜態代碼中測試接口的正確性,所以能夠經過MockMVC來模擬HTTP請求。基於RESTful風格的SpringMVC的測試,咱們能夠測試完整的Spring MVC流程,即從URL請求到控制器處理,再到視圖渲染均可以測試。後端

首先建立一個超簡單的controllerbash

@RestController
@RequestMapping(value = "/web")
public class WebController {

    @PostMapping(value = "/create")
    public WebResponse<String> ping(@RequestBody WebRequest webRequest){
        System.out.println(webRequest);
        WebResponse<String> response = new WebResponse<>();
        response.setBody("create 完成---");
        response.setCode("00000");
        response.setMessage("成功");
        return response;
    }
}
複製代碼

request和responseapp

@Data
@ToString
@EqualsAndHashCode
public class WebRequest {
    private String name;
    
    private String mobile;
}
複製代碼
@Data
@ToString
@EqualsAndHashCode
public class WebResponse<T> {
    private String code;

    private String message;

    private T body;
}
複製代碼

而後建立一個測試用例類框架

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class WebControllerIT {

    @Autowired
    private WebApplicationContext mac;

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void ping() throws Exception {
        //請求的json
        String json = "{\"name\":\"王五\",\"mobile\":\"12345678901\"}";

        //perform,執行一個RequestBuilders請求,會自動執行SpringMVC的流程並映射到相應的控制器執行處理
        mockMvc.perform(MockMvcRequestBuilders
                //構造一個post請求
                .post("/web/create")
                //json類型
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                //使用writeValueAsString()方法來獲取對象的JSON字符串表示
                .content(json))
                //andExpect,添加ResultMathcers驗證規則,驗證控制器執行完成後結果是否正確,【這是一個斷言】
                .andExpect(MockMvcResultMatchers.status().is(200))
                .andExpect(MockMvcResultMatchers.status().isOk())
                //使用jsonPaht驗證返回的json中code字段的返回值
                .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("00000"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("成功"))
                //body屬性不爲空
                .andExpect(MockMvcResultMatchers.jsonPath("$.body").isNotEmpty())
                //添加ResultHandler結果處理器,好比調試時 打印結果(print方法)到控制檯
                .andDo(MockMvcResultHandlers.print())
                //返回相應的MvcResult
                .andReturn();
    }

}
複製代碼

其中MockMvcRequestBuilders 寫好後直接運行就能夠了,從控制檯就能夠看到詳細信息。前後端分離

4 Mockito

4.1 Mockito是什麼

Mockito是mocking框架,它讓你用簡潔的API作測試。並且Mockito簡單易學,它可讀性強和驗證語法簡潔。 Mockito是GitHub上使用最普遍的Mock框架,並與JUnit結合使用.Mockito框架能夠建立和配置mock對象.使用Mockito簡化了具備外部依賴的類的測試開發!

4.2 使用Mockito

加入一個service

public interface WebService {

    String web(String string);
}
複製代碼
@Service
public class WebServiceImpl implements WebService {

    @Override
    public String web(String string) {
        return "WebServiceImpl 運行成功";
    }
}
複製代碼

修改controller

@RestController
@RequestMapping(value = "/web")
public class WebController {

    @Autowired
    private WebService webService;

    @PostMapping(value = "/create")
    public WebResponse<String> ping(@RequestBody WebRequest webRequest){

        //調用service
        String str = webService.web(webRequest.getMobile());

        WebResponse<String> response = new WebResponse<>();
        response.setBody(str);
        response.setCode("00000");
        response.setMessage("成功");
        return response;
    }
}
複製代碼

修改測試用例

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class WebControllerIT {

    @Autowired
    private WebApplicationContext mac;

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private WebService webService;

    @Test
    public void ping() throws Exception {

        doReturn("Mockito WebServiceImpl 運行完成").when(webService).web(anyString());

        //請求的json
        String json = "{\"name\":\"王五\",\"mobile\":\"12345678901\"}";

        //perform,執行一個RequestBuilders請求,會自動執行SpringMVC的流程並映射到相應的控制器執行處理
        mockMvc.perform(MockMvcRequestBuilders
                //構造一個post請求
                .post("/web/create")
                //json類型
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                //使用writeValueAsString()方法來獲取對象的JSON字符串表示
                .content(json))
                //andExpect,添加ResultMathcers驗證規則,驗證控制器執行完成後結果是否正確,【這是一個斷言】
                .andExpect(MockMvcResultMatchers.status().is(200))
                .andExpect(MockMvcResultMatchers.status().isOk())
                //使用jsonPaht驗證返回的json中code字段的返回值
                .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("00000"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("成功"))
                //body屬性不爲空
                .andExpect(MockMvcResultMatchers.jsonPath("$.body").isNotEmpty())
                //添加ResultHandler結果處理器,好比調試時 打印結果(print方法)到控制檯
                .andDo(MockMvcResultHandlers.print())
                //返回相應的MvcResult
                .andReturn();
    }

}
複製代碼

輸出結果:

從上面的代碼能夠看到,咱們新增了一個 webService,並增長了 @MockBean註解,表示將 webService給mock調,這樣咱們就能夠增長本身想要得 webService返回結果。 在測試用例中咱們增長了 doReturn()方法,這段代碼的含義是當調用 WebService中的 web()方法時( anyString()表示傳入 web()方法中的參數是任意的String類型,固然還有個 anyInt()等方法),返回 Mockito WebServiceImpl 運行完成。固然你也能夠不將 WebService給mock掉,這樣拿到的就是正常的返回值。
相關文章
相關標籤/搜索