1. 程式人生 > >spring-boog-測試打樁-Mockito

spring-boog-測試打樁-Mockito

Mockito用於測試時進行打樁處理;通過它可以指定某個類的某個方法在什麼情況下返回什麼樣的值。

例如:測試 controller時,依賴 service,這個時候就可以假設當呼叫 service 某個方法時返回指定的某些值,從而來降低引用類所帶來的測試複雜度增加的影響。Mockito就用於這種場景。

Mockito常用測試場景描述如下:

  • 指定打樁物件的返回值
  • 判斷某個打樁物件的某個方法被呼叫及呼叫的次數
  • 指定打樁物件丟擲某個特定異常

Mockito的使用,一般有以下幾種組合:

  • do/when:包括doThrow(…).when(…)/doReturn(…).when(…)/doAnswer(…).when(…)
  • given/will:包括given(…).willReturn(…)/given(…).willAnswer(…)
  • when/then: 包括when(…).thenReturn(…)/when(…).thenAnswer(…)

指定打樁物件返回值

通過Mockito指定打樁物件的返回值時,可以通過以下方式進行:

given

given用於對指定方法進行返回值的定製,它需要與will開頭的方法一起使用,will開頭的方式根據其接收引數的不同,又分成兩類:一是接收直接值的,如直接指定返回結果為某個常量;二是接收Answer引數的,可以騎過Answer類的answer方法來根據傳入引數定製返回結果。

Answer物件

我們實際針對的一般是某個類的某個方法;這個方法可能會有輸入引數;考慮這種場景:如果要假設打樁的這個方法,在某個輸入時返回值A;在另外一個輸入時返回值為B;這種場景就可以通過Answer類來實現。

案例

@RunWith(SpringRunner.class)
@SpringBootTest
public class LearnController2Test {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mvc;

    private MockHttpSession session;


    /**
     * 1. 對於不需要返回的任何值的類的所有方法,可以直接使用MockBean
     * 2. @MockBean 會代理已有的bean的方法,不會執行真實 bean 的具體方法。
     */
    @MockBean
    private LearnService learnService;

    @Before
    public void setupMockMvc() {
        //初始化MockMvc物件
        mvc = MockMvcBuilders.webAppContextSetup(wac).build();

        //構建session
        session = new MockHttpSession();
        User user = new User("root", "root");
        //攔截器那邊會判斷使用者是否登入,所以這裡注入一個使用者
        session.setAttribute("user", user);
    }


    /**
     * 獲取教程測試用例
     * <p>
     * get 請求
     * <p>
     * controller 依賴 service 的方法,這裡給 service 方法打樁,不執行真實的方法
     *
     * @throws Exception
     */
    @Test
    public void qryLearn() throws Exception {

        LearnResource learnResource = new LearnResource();
        learnResource.setUrl("http://www.baidu.com");
        learnResource.setTitle("zhang");
        learnResource.setAuthor("zhang");
        learnResource.setId(10L);

        // 當呼叫 selectByKey 函式時,返回指定的值
        given(this.learnService.selectByKey(Mockito.any())).willAnswer(new Answer<Object>() {

            /**
             * InvocationOnMock 通過它可以獲取打樁方法的實際傳入引數清單
             * @param invocationOnMock
             * @return
             * @throws Throwable
             */

            @Override
            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                Long argumentAt = invocationOnMock.getArgumentAt(0, Long.class);
                System.out.println("呼叫方法的實際引數: " + argumentAt);
                if (argumentAt.equals(Long.parseLong("1001"))) {
                    return learnResource;
                }
                return null;
            }
        });

        mvc.perform(MockMvcRequestBuilders.get("/learn/resource/1001")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .session(session)
        )
                .andExpect(MockMvcResultMatchers.status().isOk())
                //jsonPath用來獲取author欄位比對是否為嘟嘟MD獨立部落格,不是就測試不通過
                .andExpect(MockMvcResultMatchers.jsonPath("$.author").value("嘟嘟MD獨立部落格"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("Spring Boot乾貨系列"))
                .andDo(MockMvcResultHandlers.print());
    }


}

參考

https://blog.csdn.net/icarusliu/article/details/78860351