springboot2.1.3+Junit4 单元测试

引入依赖的包:java

<dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-core</artifactId>
      <version>2.23.4</version>
      <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-core</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>

 

MockMvc + PowerMock + Mockito 来模拟post get请求,并mock掉service中存在doGet doPost外部系统的restful请求web

@RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(SpringRunner.class) @prepareForTest({ HttpUtil.class             // doGet doPost 使用util类,这里须要告诉UT
}) @PowerMockIgnore("javax.crypto.*") @AutoConfigureMockMvc @SpringBootTest public class DemoSzlTest { @Autowired private WebApplicationContext webApplicationContext; private MockMvc mockMvc; @Before public void setUp() throws Exceptioin { MockitoAnnotations.initMocks(this); // 初始化装载powerMockito
           mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } @Test @DirtiesContext public void testPostDemo() throws Exception { // mock HttpResponse 对象返回
            StringEntity se = new StringEntity("xxxxxx", "utf-8"); HttpResponse resp = new BasicHttpResponse(new BasicStatusLine(HttpVersion.Http_1_1, HttpServletResponse.SC_OK, "")); resp.setEntity(se); PowerMockito.mockStatic(HttpUtil.class);
// 这里的 Mockito.anyString() 要和 实际方法参数保持一致
PowerMockite.when(HttpUtil.doGet(Mockito.anyString(), Mockito.anyMap(), Mockito.any())).thenReturn(resp); // 这里不 mock方法,直接走真实场景方法
PowerMockito.when(HttpUtil.toJson(Mockito.anyObject())).thenCallRealMethod();
// body contents String jsonBody = "{\"aaaa\":\"1111\"}"; String token = "xxxxx"; MvcResult resultMsg = mockMvc.perform( post("/xxx") .contentType(MediaType.APPLICATION_JSON_VALUE) .accept(MediaType.APPLICATION_JSON_UTF8_VALUE) .header("xxxxx", token) .content(jsonBody) // request body ).andExpect(status().isCeated()) .andReturn(); }


    @Test
    @DirtiesContext
    public void contextLoads() throws Exception {
        // 这里定义的 header 值 必需要和service层使用的值保持一致,不然powerMock mock时会有问题
        // 其实也很好理解,既然要mock,那就作到真实一点,一切都保持如出一辙便可。
        Header[] header = {
                new BasicHeader("Authorization", "aaabbbccc"),
                new BasicHeader("Content-Type", "application/json")
            };
        
        // 手动建立HttpResponse,来模式http请求的返回值
        StringEntity se = new StringEntity("{"
                + "\"memo\":\"这个只是demo式样\"}", "utf-8");
        HttpResponse resp = new BasicHttpResponse(new BasicStatusLine(HttpVersion.HTTP_1_1,
                HttpServletResponse.SC_OK, ""));
        resp.setEntity(se);
        
        // 和上面说明一致
        StringEntity se2 = new StringEntity("{"
                + "\"memo\":\"这个只是demo2式样\"}", "utf-8");
        HttpResponse resp2 = new BasicHttpResponse(new BasicStatusLine(HttpVersion.HTTP_1_1,
                HttpServletResponse.SC_OK, ""));
        resp2.setEntity(se2);
        
        // 开始mock咱们想要的静态方法,此处是mock post请求并返回上面咱们mock的值
        PowerMockito.mockStatic(HttpUtil.class);
        /**
         * 本人是为了达到一个service里连续调用2次post请求,但2次请求内容不一样,返回结果也不一样,进行mock
         * Mockito.eq("/aaa")               是mock值
         * Mockito.eq("aaabbb")             是mock值
         * Mockito.any(header.getClass())   是mock Header[]值
         */
        PowerMockito.when(HttpUtil.doPost(Mockito.eq("/aaa"), Mockito.eq("aaabbb"), Mockito.any(header.getClass()))).thenReturn(resp);
        PowerMockito.when(HttpUtil.doPost(Mockito.eq("/bbb"), Mockito.eq("cccddd"), Mockito.any(header.getClass()))).thenReturn(resp2);
        
        String jsonBody = "{\"aaaa\":\"1111\"}";
        String token = "xxxxx";
        MvcResult resultMsg = mockMvc.perform(
                 post("/testUTDemo")
                 .header("Authorization", token)
                 .content(jsonBody)    // request body
        ).andExpect(status().isCreated()).andReturn();
    } }

 

Controller类:spring

package com.szl.demo.szldemo.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import com.szl.demo.szldemo.common.dto.UserDto; import com.szl.demo.szldemo.service.UserService; import lombok.extern.slf4j.Slf4j; @Slf4j @Controller public class DemoController { @Autowired private UserService userService; @ResponseBody @RequestMapping(value = "/testUTDemo", method = RequestMethod.POST) public UserDto testUTDemo(HttpServletRequest request, HttpServletResponse response) { return userService.testDemoUnitTest(); } }

 

Service接口:apache

package com.szl.demo.szldemo.service; import com.szl.demo.szldemo.common.dto.UserDto; public interface UserService { UserDto testDemoUnitTest(); }

 

Service实现类:json

package com.szl.demo.szldemo.service.impl; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.message.BasicHeader; import org.springframework.stereotype.Service; import com.szl.demo.szldemo.common.dto.UserDto; import com.szl.demo.szldemo.common.util.HttpUtil; import com.szl.demo.szldemo.service.UserService; import lombok.extern.slf4j.Slf4j; @Slf4j @Service("userService") public class UserServiceImpl implements UserService { public UserDto testDemoUnitTest() { try { Header[] header = { new BasicHeader("Authorization", "aaabbbccc"), new BasicHeader("Content-Type", "application/json") }; 
// 此处的代码块也是mock的重点 HttpResponse resp
= HttpUtil.doPost("/aaa", "aaabbb", header); HttpEntity entity = resp.getEntity(); String msg = IOUtils.toString(entity.getContent(), "UTF-8"); log.info("msg: " + msg);
// 同上 HttpResponse resp2
= HttpUtil.doPost("/bbb", "cccddd", header); HttpEntity entity2 = resp2.getEntity(); String msg2 = IOUtils.toString(entity2.getContent(), "UTF-8"); log.info("msg2: " + msg2); } catch (Exception e) { e.printStackTrace(); }
// 这里随便赋值并返回,主要不是看这里的功能 UserDto dto
= new UserDto(); dto.setId(1001L); dto.setNickName("test"); dto.setUserId(10000001L); return dto; } }

 

HttpUtil.java类:api

public class HttpUtil { public static HttpResponse doGet(String url, Map<String, String> params, Header[] headers) { ..... 这里省略 }

public static JsonObject toJson(HttpResponse httpResponse) {
.....
这里省略

}
public static HttpResponse doPost(String url, String params, Header[] header) {
        // 这里只是为了演示,手动建立StringEntity并赋值,手动建立HttpResponse并返回
        HttpResponse resp = new BasicHttpResponse(new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, null));
        StringEntity se1 = new StringEntity("{"
                + "\"alg\":\"aqas\","
                + "\"id\":\"122011\"}", "utf-8");
        resp.setEntity(se1);
        return resp;
}
}

 

UserDto类: restful

package com.szl.demo.szldemo.common.dto; import java.io.Serializable; import lombok.Data; @Data public class UserDto implements Serializable { private static final long serialVersionUID = -8858511759866491158L; private Long id; private Long userId; private String nickName; }

 

 

好了,让咋们来试试上面的UT跑出什么结果,以下图:app

 

OK, 大功告成,若有博友须要,供参考,需转发,请注明引自连接,谢谢。post

 

另附上额外功能,若是有朋友须要在UT里按顺序执行,须要加注解:ui

@FixMethodOrder(xxx)

这里的xxx有三种模式:

- 默认(MethodSorters.DEFAULT)
- 按方法名(MethodSorters.NAME_ASCENDING)
- JVM(MethodSorters.JVM)

一开始本人使用JVM模式,虽然能达到预期,但运行不太稳定,本人仍是推荐你们使用NAME_ASCENDING模式

 

若有朋友参考本人的笔记,有问题能够留言,转载请注明原著,谢谢。