响应式编程中OnErrorResume功能的JUnit测试方案咨询
响应式WebClient错误场景的JUnit测试解决方案
问题根源
你当前测试的核心问题是:用doThrow让myWebClient.getResponse()直接抛出异常,但响应式方法的设计是返回包含错误信号的Mono,而非直接抛出异常。这种直接抛出的异常会在赋值responseDataMono时就中断执行,根本无法进入后续的onErrorResume错误处理逻辑。
正确测试方案
1. 模拟WebClient返回带错误的Mono
不要用doThrow,而是让getResponse返回一个包含目标异常的Mono.error(),这样才能让响应式流正常流转到onErrorResume。
2. 触发响应式流执行
响应式流是惰性的,仅仅调用myServiceMethod()获取Mono不会执行任何逻辑,必须调用block()或者subscribe()来触发流的执行。
3. 验证错误处理逻辑
可以通过Mockito的参数捕获器、行为验证,或者断言最终结果来确认错误处理逻辑是否被正确触发。
修改后的测试代码
@RunWith(MockitoJUnitRunner.class) public class ServiceTest { @InjectMocks private MyService myServiceMock; @Mock private MyWebClient myWebClient; @Test // 必须添加@Test注解,否则测试不会被执行 public void testErrorCode400() { // 模拟WebClient返回包含400异常的Mono when(myWebClient.getResponse(anyString())) .thenReturn(Mono.error(new WebClientResponseException(400, "Bad Request", null, null, null))); // 触发响应式流执行 Mono<Student> resultMono = myServiceMock.myServiceMethod(); Student result = resultMono.block(); // block()会触发流执行并等待结果 // 验证结果:因为onErrorResume返回Mono.empty(),所以block()会得到null Assert.assertNull(result); // 如果需要验证错误处理逻辑中的特定行为(比如日志、其他方法调用),可以用verify // 示例:verify(logger).error(anyString(), any(WebClientResponseException.class)); } @Test public void testTimeoutException() { // 模拟超时异常场景 when(myWebClient.getResponse(anyString())) .thenReturn(Mono.error(new io.netty.handler.timeout.TimeoutException())); Mono<Student> resultMono = myServiceMock.myServiceMethod(); Student result = resultMono.block(); Assert.assertNull(result); // 可在此添加超时错误逻辑的验证代码 } }
服务代码优化建议(可选)
你的服务代码可以简化冗余判断,去掉不必要的强转和冗余操作:
// 假设MyWebClient.getResponse返回的就是Mono<Student>,无需强转 Mono<Student> responseDataMono = myWebClient.getResponse("url"); return responseDataMono .onErrorResume(ex -> { if (ex instanceof WebClientResponseException webEx) { if (webEx.getStatusCode() == HttpStatus.NOT_FOUND) { // 404处理逻辑 } else if (webEx.getStatusCode() == HttpStatus.BAD_REQUEST) { // 400处理逻辑 } } else if (ex instanceof io.netty.handler.timeout.TimeoutException) { // 超时处理逻辑 } else { // 其他错误处理逻辑 } return Mono.empty(); }); // 原代码中的map(resp -> resp)是冗余操作,可直接移除
内容的提问来源于stack exchange,提问作者Sweety
相关产品推荐
相关产品推荐

