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中有了 更清晰的了解.