Spring Boot Test:使用ExpectedCount.manyTimes()无法持久化预期请求
我正在对代码进行集成测试,使用spring-boot-test中的MockRestServiceServer来设置预期请求。测试中有一个请求会被多次调用,但它似乎无法在测试过程中持久生效。
测试代码
@Test void getHealthStatus() { try { RequestBuilder request = get("/actuator/hc").contentType("application/json"); MockServerBinder.bindPersistentThingworxPropertiesCall( mockServer, requestTo(new URI(String.format("%sProperties/TestProp", thingworxUrl))), objectMapper.writeValueAsString(new PingResponse(DashboardIndicator.HEALTHY, 200)) ); DashboardStatusModel expectedResult = new DashboardStatusModel(); expectedResult.addResult("spring",service.getAppHealth()); expectedResult.addResult("thingworx", service.getThingworxAvailability()); assertOpenUrl(request); MvcResult result = mockMvc.perform(get("/actuator/hc").contentType("application/json")) .andExpect(status().isOk()) .andReturn(); DashboardStatusModel actualResult = objectMapper.readValue(result.getResponse().getContentAsString(), DashboardStatusModel.class); assertEquals(expectedResult.getResults().get("spring"), actualResult.getResults().get("spring")); assertEquals(expectedResult.getResults().get("thingworx").getStatus(),actualResult.getResults().get("thingworx").getStatus()); assertEquals(expectedResult.getResults().get("thingworx").getData().get("url"), actualResult.getResults().get("thingworx").getData().get("url")); } catch (Exception e) { fail("Unable to perform REST call on GDP-API", e); } }
补充信息
- mockServer在父类中创建:
protected static MockRestServiceServer mockServer; @BeforeEach public void configureMockServer() { mockServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build(); }
MockServerBinder.bindPersistentThingworxPropertiesCall()辅助类代码:
public static void bindPersistentThingworxPropertiesCall(MockRestServiceServer mockServer, RequestMatcher request, String responseJSONasString){ mockServer.expect(ExpectedCount.once(), request) .andExpect(method(HttpMethod.GET)) .andRespond(withStatus(HttpStatus.OK) .contentType(MediaType.APPLICATION_JSON) .body(responseJSONasString)); }
assertOpenUrl(request)函数用于通过MockMVC检查URL是否无需认证:
public void assertOpenUrl(RequestBuilder request){ try{ mockMvc.perform(request).andExpect(status().isOk()); } catch (Exception e) { fail("Unable to perform REST call on GDP-API", e); } }
运行测试时,expectedResult.addResult("thingworx", service.getThingworxAvailability())可以正常使用MockRestServiceServer,但assertOpenUrl(request)会失败,因为MockRestServiceServer不再预期对绑定端点的调用。如果重复调用MockServerBinder.bindPersistentThingworxPropertiesCall()则不会出现问题,因此我认为是请求绑定方式有问题。
据我了解,ExpectedCount.manyTimes()应该能让该请求在测试期间保持可用,请问这个理解是否正确?或者有没有其他绑定请求的方法能让它在整个测试中持续生效?
你的理解是正确的,ExpectedCount.manyTimes()确实可以让MockRestServiceServer允许该请求被调用任意次数,而非默认的仅一次。
方法一:修改辅助方法使用manyTimes()
直接替换辅助方法中的ExpectedCount.once()为ExpectedCount.manyTimes(),即可让该请求预期在整个测试过程中重复生效:
public static void bindPersistentThingworxPropertiesCall(MockRestServiceServer mockServer, RequestMatcher request, String responseJSONasString){ mockServer.expect(ExpectedCount.manyTimes(), request) .andExpect(method(HttpMethod.GET)) .andRespond(withStatus(HttpStatus.OK) .contentType(MediaType.APPLICATION_JSON) .body(responseJSONasString)); }
方法二:重置预期(动态场景适用)
如果需要在测试过程中动态调整预期,可以调用mockServer.reset()清空已有预期,再重新绑定请求。不过这个方法更适合需要频繁变更预期的场景,你的需求用第一种方法更直接。
注意事项
- 你已经开启的
ignoreExpectOrder(true)配置是正确的,它会让MockRestServiceServer不严格校验请求的调用顺序,避免因多次调用顺序问题导致的失败。 - 由于
@BeforeEach会在每个测试方法执行前重新创建mockServer,所以每个测试的预期都是独立的,不会和其他测试产生干扰。
内容的提问来源于stack exchange,提问作者BT_Code

