zoukankan      html  css  js  c++  java
  • springboot2.1.3+Junit4 单元测试

    引入依赖的包:

    <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请求

    @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类:

    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接口:

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

    Service实现类:

    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类:

    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类: 

    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跑出什么结果,如下图:

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

    另附上额外功能,如果有朋友需要在UT里按顺序执行,需要加注解:

    @FixMethodOrder(xxx)

    这里的xxx有三种模式:

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

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

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

  • 相关阅读:
    fenby C语言P21
    fenby C语言 P20
    fenby C语言 P19
    fenby C语言 P18
    fenby C语言 P17
    fenby C语言 P16
    fenby C语言 P15
    fenby C语言 P14
    Python学习之路:subprocess模块和面向对象
    Python学习之路:XML模块
  • 原文地址:https://www.cnblogs.com/jimmyshan-study/p/11012121.html
Copyright © 2011-2022 走看看