WireMock调用超时问题:如何确保Stub就绪后再执行测试?
确保WireMock Stub就绪后执行HTTP调用的解决方案
你遇到的这个超时问题很典型——虽然stubFor()是同步调用,但在Spring Boot集成测试+协程的场景下,偶尔会出现实际服务调用比WireMock Stub完全就绪要快的情况,导致请求超时。下面给你几个经过验证的解决方案:
方法一:主动验证Stub可用性(最可靠)
注册Stub之后,先发送一个测试请求到WireMock,并用verify()方法等待这个请求被处理,以此确认Stub已经生效:
@Test fun `without travel ads returns sorted organic properties`() { // 1. 注册你的Stub stubFor(post(urlEqualTo("/myApi")) .willReturn(aResponse() .withHeader("Content-Type", "application/x-protobuf") .withBody(stubResponse.toByteArray()))) // 2. 先发送一个测试请求到WireMock,验证Stub能响应 val testClient = HttpClient.newHttpClient() val testRequest = HttpRequest.newBuilder() .uri(URI.create("http://localhost:${wireMockServer.port()}/myApi")) .POST(HttpRequest.BodyPublishers.ofByteArray(byteArrayOf())) .build() testClient.send(testRequest, HttpResponse.BodyHandlers.discarding()) // 3. 等待测试请求被命中(设置5秒超时,足够Stub就绪) verify(times(1), within(5000), postRequestedFor(urlEqualTo("/myApi"))) // 4. 现在再执行实际的服务调用 val actualResponse = runBlocking { myService.getUserData() } // 你的断言逻辑 <<<<部分断言>>>> }
注意:要使用这个方法,你需要在BaseIT类里注入WireMockServer实例:
@Autowired lateinit var wireMockServer: WireMockServer
方法二:用WireMock的waitFor API等待Stub状态
WireMockServer提供了waitFor()方法,可以自定义等待条件,比如检查我们注册的Stub是否已经存在于WireMock的映射列表中:
@Test fun `without travel ads returns sorted organic properties`() { // 注册Stub时保存它的ID val stubId = stubFor(post(urlEqualTo("/myApi")) .willReturn(aResponse() .withHeader("Content-Type", "application/x-protobuf") .withBody(stubResponse.toByteArray()))) // 等待Stub就绪,最多等5秒 wireMockServer.waitFor(5000) { wireMockServer.stubMappings().any { it.id == stubId } } // 执行实际调用 val actualResponse = runBlocking { myService.getUserData() } // 断言部分 <<<<部分断言>>>> }
方法三:优化协程执行时序
因为你用了runBlocking执行协程调用,可能存在协程调度比Stub注册生效快的情况。可以试试切换到IO调度器,或者添加一个微小的延迟(应急可用):
@Test fun `without travel ads returns sorted organic properties`() { stubFor(post(urlEqualTo("/myApi")) .willReturn(aResponse() .withHeader("Content-Type", "application/x-protobuf") .withBody(stubResponse.toByteArray()))) // 切换到IO调度器,给Stub足够的生效时间 val actualResponse = runBlocking(Dispatchers.IO) { delay(100) // 可选:添加100ms延迟,确保Stub完全就绪 myService.getUserData() } // 断言部分 <<<<部分断言>>>> }
方法四:全局配置WireMock超时
如果不想在每个测试里加验证逻辑,也可以在application-dev.properties里全局设置WireMock的超时时间,给Stub足够的就绪窗口:
# 设置WireMock的请求和响应超时为10秒 wiremock.server.request-timeout=10000 wiremock.server.response-timeout=10000
总结
优先推荐方法一和方法二,它们是主动验证Stub就绪的方式,比单纯延长超时更可靠;方法三适合协程场景下的快速调整;方法四作为全局兜底配置使用。
内容的提问来源于stack exchange,提问作者robin
相关产品推荐
相关产品推荐

