Spring中使用Mockito模拟WebClient返回JSON响应的实现问题
实现方案
首先明确你现有代码的两个核心问题:
- 测试方法中手动给
webClient重新赋值为真实构建的实例,覆盖了@Mock生成的代理对象,导致@InjectMocks注入失效,且无服务配置的真实WebClient调用必然报错 - WebClient是链式调用结构,需要逐层模拟每一步调用的返回对象,不能直接模拟单一方法
完整实现步骤
1. 基础依赖确认
Spring Boot项目引入spring-boot-starter-test即可自带Mockito、Reactor测试相关依赖,无需额外引入。
2. 测试代码示例
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.assertEquals; // JUnit4版本替换为 @RunWith(MockitoJUnitRunner.class) @ExtendWith(MockitoExtension.class) public class TranslateDaoTest { @Mock private WebClient webClient; @Mock private WebClient.RequestHeadersUriSpec requestHeadersUriSpec; @Mock private WebClient.RequestHeadersSpec requestHeadersSpec; @Mock private WebClient.ResponseSpec responseSpec; @InjectMocks private TranslateDao translateDao; @Test void getTestReturnExpectedResult() { // 构造期望返回的模拟数据,对应你要返回的JSON结构字段 Test expectedResult = new Test(); expectedResult.setId(123); expectedResult.setName("测试返回值"); // 逐层模拟WebClient链式调用 when(webClient.get()).thenReturn(requestHeadersUriSpec); // 用eq精确匹配你业务代码中写死的uri地址,也可以用anyString()模糊匹配 when(requestHeadersUriSpec.uri(eq("url"))).thenReturn(requestHeadersSpec); when(requestHeadersSpec.retrieve()).thenReturn(responseSpec); when(responseSpec.bodyToMono(Test.class)).thenReturn(Mono.just(expectedResult)); // 执行测试方法 Test actualResult = translateDao.getTest("qw"); // 结果断言 assertEquals(expectedResult.getId(), actualResult.getId()); assertEquals(expectedResult.getName(), actualResult.getName()); } }
简化写法(无需提前声明逐层Mock对象)
@Test void getTestShorterVersion() { Test expectedResult = new Test(); expectedResult.setId(123); when(webClient.get()).thenReturn(mock(WebClient.RequestHeadersUriSpec.class)); when(webClient.get().uri(eq("url"))).thenReturn(mock(WebClient.RequestHeadersSpec.class)); when(webClient.get().uri(eq("url")).retrieve()).thenReturn(mock(WebClient.ResponseSpec.class)); when(webClient.get().uri(eq("url")).retrieve().bodyToMono(Test.class)).thenReturn(Mono.just(expectedResult)); Test actual = translateDao.getTest("test"); assertEquals(expectedResult.getId(), actual.getId()); }
扩展场景
如果需要模拟调用失败的异常场景,只需把bodyToMono的返回值替换为错误Mono即可:
when(responseSpec.bodyToMono(Test.class)).thenReturn(Mono.error(new RuntimeException("调用远端服务失败")));
内容的提问来源于stack exchange,提问作者Arczi
相关产品推荐
相关产品推荐

