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

场景

在一次开发过程中遇到了需要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;
            }
        };
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容