美文网首页
《单元测试篇》jmockit实现接口mock时异常

《单元测试篇》jmockit实现接口mock时异常

作者: 云天河_ | 来源:发表于2022-03-12 16:55 被阅读0次

    场景

    在一次开发过程中遇到了需要mock合作方接口,但是使用了常用的mock方式却出现了异常。

    问题

    但在使用jmockit的@Mocked模拟方式时总报错,如下:

    java.lang.IllegalArgumentException: Invalid type for partial mocking: interface com.test.common.gateway.PanterGatewayService
        at com.test.common.gateway.TestMockTest$1.<init>(TestMockTest.java:32)
        at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
        at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    

    实现代码如下:

    public class BizMockTest extends SpringTestCase {
       @Resource
        private GatewayService gatewayService;
    
        @Before
        public void before() {
               new Expectations(gatewayService) {
                {
                    gatewayService.queryLimit((CommonRequest<LimitQueryRequest>) any);
                    CommonResponse<LimitQueryResponse> response = new CommonResponse();
                    response.setCode("000000");
                    response.setDesc("SUCCESS");
                    response.setResponse(LimitQueryResponse.builder()
                            .sumAmt(BigDecimal.valueOf(100000))
                            .leftAmt(BigDecimal.valueOf(100000))
                            .quotaState("3")
                            .build());
                    result = response;
                }
            };
        }
    

    分析

    以往mock代码如下均没问题,那这个又是为什么呢?对比之下发现原来 GatewayService 是在配置加载时@Configuration才初始化Bean,也就是运行时初始化,而且也没有实现类。

    如下:

    @Configuration
    public class InitConfig {
     @Bean("GatewayService")
        public GatewayService gatewayService() {
            return Feign.builder()
                    .client(new OkHttpClient())
                    .retryer(Retryer.NEVER_RETRY)
                    .logger(new Slf4jLogger())
                    .logLevel(Logger.Level.FULL)
                    .target(GatewayService.class);
        }
    

    解决方案

    经过查阅jmockit的API找到了如下方式实现。

    方式一:通过 @Capturing 注解实现;

    public class Test extends SpringTestCase {
        @Resource
        private GatewayService  gatewayService;
    
        // 在单元测试放在中使用 @Capturing 可以实现mock接口,所有实现类的实例均被mock
        @Test
        public void testLoanInit(@Capturing final GatewayService gatewayService) {
            new Expectations() {
                {
                    gatewayService.queryLimit((CommonRequest) any);
                    CommonResponse response = new CommonResponse();
                    response.setCode("000000");
                    response.setDesc("SUCCESS");
                    response.setResponse(LimitQueryResponse.builder()
                            .sumAmt(BigDecimal.valueOf(100000))
                            .leftAmt(BigDecimal.valueOf(100000))
                            .quotaState("3")
                            .build());
                    result = response;
                }
            };
    
            CommonResponse commonResponse =  gatewayService.queryLimit(new CommonRequest());
            // 输出:{"code":"000000","desc":"SUCCESS","response":{"leftAmt":100000,"quotaState":"3","sumAmt":100000}}
            System.out.println(JSONObject.toJSONString(limitQueryCommonResponse));
            // 调用方法
            invokeTest();
        }
      
        
        public void invokeTest() {
          CommonResponse commonResponse =  gatewayService.queryLimit(new CommonRequest());
           // 输出:{"code":"000000","desc":"SUCCESS","response":{"leftAmt":100000,"quotaState":"3","sumAmt":100000}}
           System.out.println(JSONObject.toJSONString(limitQueryCommonResponse));
        }
    }
    

    方式二:自己写一个假接口实现类,即可使用原来的方式,或者直接再mock实现类中实现模拟返回 ;

    // 写一个mock实现类
    @Service("gatewayService")
    public class GatewayServiceMockImpl implements GatewayService {
    
        @Override
        public CommonResponse<LimitQueryResponse> queryLimit(CommonResponse<LimitQueryResponse> request) {
          // mock 数据返回或使用 @Mocked 方式构造返回数据
            return null;
        }
    }
    

    有了一个接口实现,即可使用 @Mocked 方式 mock了;

    public class BizMockTest extends SpringTestCase {
       @Resource
        private GatewayService gatewayService;
    
        @Before
        public void before() {
               new Expectations(gatewayService) {
                {
                    gatewayService.queryLimit((CommonRequest<LimitQueryRequest>) any);
                    CommonResponse<LimitQueryResponse> response = new CommonResponse();
                    response.setCode("000000");
                    response.setDesc("SUCCESS");
                    response.setResponse(LimitQueryResponse.builder()
                            .sumAmt(BigDecimal.valueOf(100000))
                            .leftAmt(BigDecimal.valueOf(100000))
                            .quotaState("3")
                            .build());
                    result = response;
                }
            };
        }
    

    相关文章

      网友评论

          本文标题:《单元测试篇》jmockit实现接口mock时异常

          本文链接:https://www.haomeiwen.com/subject/ezardrtx.html