首页 > 技术文章 > springboot 中 Mock 三方接口测试service类

idea-persistence 原文

1、背景

在 业务逻辑中间需要调用 三方部门的接口,但三方接口还在开发中,只提供了 接口名称,自己业务已经开发完成,所以需要Mock 掉单三方的 调用。

2、 使用Mock进行测试

需求是 要 部分mock的形式(只mock 三方的接口),其他 bean 使用真实的实例。

使用 @SpringbootTest, 启动容器测试。

调用方法1相关的部分链路

XxxInfoService->XxxInfoService: 测试目标方法类
XxxInfoService->XxxApiService: 三方接口
XxxInfoService->XxxInvokeService: 操作db
XxxInfoService->....: 其他操作
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class MockTest {
    /**
     * 其他 未 定义 @Mock 的类,通过 spring注入到 IOC中
     */
    @Autowired
    @InjectMocks
    private XxxInfoService xxxInfoService;

    //需要 mock 执行的 类
    @Mock
    private XxxApiService xxxApiService;


    @Before
    public void init() {
      //Mock IOC
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void test() throws IOException {

        //同@Mock 二选一
//        xxxApiService = Mockito.mock(XxxApiService.class);
        XxxResponseBase responseBase =  new XxxResponseBase();
        responseBase.setCode(0);
      	//Mock 三方接口的 result
        Mockito.when(xxxApiService.feedbackOrderSubmit(any()))
                .thenReturn(responseBase);

        Config config = new Config();
        config.setOrderId("123");
        xxxInfoService.notifyOss(config);
    }
}

结果:执行成功,并且 db中插入 记录

调用方法2的 部分调用链路,所有数据的获取都需要mock

XxxInfoService->XxxInfoService: 测试目标方法类
XxxInfoService->XxxApiService: 三方接口 mock
XxxInfoService->XxxService: 查询 mock
XxxInfoService->aaaService: 三方接口 mock
XxxInfoService->XxxInvokeService: 操作db
XxxInfoService->....: 其他操作
public void test_syncData() {

        String orderId="1";
        List<InfoDO> successServers= Arrays.asList(new InfoDO());
        InfoConfig infoConfig= new InfoConfig();
        infoConfig.setBasicConfig(new BasicConfig());
        infoConfig.getBasicConfig().setOrderId(orderId);
        infoConfig.getBasicConfig().setWid("1");
        infoConfig.getBasicConfig().setCid(1);
        infoConfig.getBasicConfig().setServiceId(2);
        infoConfig.getBasicConfig().setIpServiceId(3);
        infoConfig.getBasicConfig().setBwServiceId(4);

        XxxOrderDO order = new XxxOrderDO();
        order.setDesc("test");
        Mockito.when(orderService.getOrder(any())).thenReturn(order);

        ServerInfo serverInfo = new ServerInfo();

        serverInfo.setDetail(new XxxDetailResponse.Detail());
        serverInfo.getDetail().setInfo(new XxxDetailResponse.Info());
        serverInfo.getDetail().getInfo().setOsName("os");
        serverInfo.getDetail().getInfo().setLcUuid("uuid");
        serverInfo.getDetail().getInfo().setLabel("lable");
        serverInfo.getDetail().getInfo().setSn("sn");
        serverInfo.getDetail().getInfo().setOrderId(123);
        serverInfo.getDetail().getInfo().setZoneName("Lax");
        serverInfo.getDetail().getInfo().setName("pre");
        serverInfo.getDetail().getInfo().setStartTime("2020-12-12 10:12:12");
        serverInfo.getDetail().getInfo().setOwnWanIp("10.10.10.10");

        serverInfo.getDetail().getInfo().setWanLanId(0);

        serverInfo.getDetail().getInfo().setWanSwIfname("ddff");
        serverInfo.getDetail().getInfo().setSnmpIp("10.22.22.22");
        Mockito.when(aaaService.serverDetail(any(),any())).thenReturn(serverInfo);

        xxxResponseBase responseBase =  new xxxResponseBase();
        responseBase.setCode(0);
        Mockito.when(xxxApiService.synaaaData(any())).thenReturn(responseBase);

       //场景1 
        xxxInfoService.syncData(successServers, infoConfig, true,orderId);


        // 场景 2
        serverInfo.getDetail().getInfo().setWanLanId(1);
        GetVpcVlanResponse response = new GetVpcVlanResponse();
        response.setData(new GetVpcVlanResponse.Data());
        response.getData().setPortName("port--");
        response.getData().setSnmpIP("122--");
        GetVpcVlanResponse.Server server = new GetVpcVlanResponse.Server();
        server.setLcuuid("111");
        response.getData().setServers(Arrays.asList(server));
        response.setSuccess(true);
        Mockito.when(aaaService.getVpc(any(),any())).thenReturn(response);

        ServerDetailListResponse serverDetailListResponse = new ServerDetailListResponse();
        XxxDetailResponse.Detail detail = new XxxDetailResponse.Detail();
        XxxDetailResponse.Info info = new XxxDetailResponse.Info();
        info.setSnmpIp("33");
        info.setWanSwIfname("info-33");
        detail.setInfo(info);
        serverDetailListResponse.setDetail(Arrays.asList(detail));
        serverDetailListResponse.setSuccess(true);
        Mockito.when(aaaService.serverDetails(any(),any())).thenReturn(serverDetailListResponse);

        xxxInfoService.syncData(successServers, infoConfig, true,orderId);
        
        //场景3 faied
        xxxInfoService.syncData(new ArrayList<>(), infoConfig, true,orderId);
    }

3、在查询资料过程中,看到

大概浏览了下下 Mock文档, 看了一些基本的操作, 还在 Testing in Spring Boot 中发现,并不需要启动整个环境进行测试,在上面的测试中,自己也有感觉,这是用到了几个类,启动整个环境太重了。 可以通过不同的注解 分层测试。有兴趣大家可以自己看看。

  • Integration Testing With@DataJpaTest

  • Mocking With @MockBean

    • 结合 @TestConfiguration 加载 Bean
  • Unit Testing With @WebMvcTest

总结

1、Mockito 框架功能很多,我只差了 我要用到的部分,
2、为了能更好的分层测试,在代码编写过程中注意 分层。
3、操作数据多的情况下,工作量还是很大的。
4、对静态类的Mock 需要使用PowerMock。
5、typora 中画图功能强大。

mock 使用2中有了 更清晰的了解.

推荐阅读