You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 16:31:18