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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 22:48:03