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

WebTestClient调用接口无法获取JpaRepository已存数据的方案咨询

问题:Spring Boot集成测试中WebTestClient无法读取测试线程插入的数据

我编写了一个Spring Boot集成测试用例:先通过dataRepository.saveAndFlush()插入数据,测试方法内直接调用dataRepository.findAll()能查到该数据,但使用WebTestClient调用/api/constant接口时,接口中同样调用dataRepository.findAll()却返回null。

Controller代码

@RequestMapping(value = "/api/constant")
public class ConfigurationController {

  @Autowired
  private DataRepository dataRepository;

  @GetMapping
  public Mono<Object> getConstant() {
    Mono.fromSupplier(() -> this.dataRepository.findAll()).subscribeOn(Schedulers.single());
  }
}

测试类代码

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureWebTestClient
@Transactional
public class TestITCase {

  @Autowired
  private DataRepository dataRepository;

  @Autowired
  private WebTestClient webTestClient;

  @Test
  public void getConstants_Valid_Success()  {
    this.dataRepository.saveAndFlush(data);
    this.dataRepository.findAll(); // 数据存在
    FluxExchangeResult<String> result = this.webTestClient.get()
        .uri(b -> b.path("/api/constant")
            .build())
        .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
        .exchange()
        .returnResult(String.class)
        .getResponseBody()
        .blockFirst(); // 此处返回null
  }
}

更新:已知WebTestClient的请求会在不同线程处理,因此使用了新事务。现想咨询是否可以让WebTestClient运行在同一线程,因为不想提交事务再回滚,避免测试失败导致数据残留,破坏测试幂等性。


解决方案

核心原因分析

  1. 测试类的@Transactional事务绑定在测试线程上,WebTestClient默认用异步线程处理请求,异步线程无法访问测试线程中未提交的事务数据。
  2. Controller代码存在错误:方法创建了Mono但未返回,且subscribeOn(Schedulers.single())强制切换线程,导致事务上下文丢失。

步骤1:修复Controller代码

首先要确保Controller正确返回响应,且避免不必要的线程切换:

@RequestMapping(value = "/api/constant")
public class ConfigurationController {

  @Autowired
  private DataRepository dataRepository;

  @GetMapping
  public Mono<List<Object>> getConstant() {
    // 直接返回由Repository查询生成的Mono,不强制切换线程
    return Mono.fromSupplier(dataRepository::findAll);
  }
}

步骤2:让WebTestClient在测试线程同步执行

通过配置WebTestClient使用同步调度器,让请求处理与测试线程在同一线程,从而共享事务上下文:

自定义WebTestClient配置(测试类中)

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@Transactional
public class TestITCase {

  @Autowired
  private DataRepository dataRepository;

  @Autowired
  private ApplicationContext context;

  private WebTestClient webTestClient;

  @BeforeEach
  void setUp() {
    // 绑定到应用上下文,指定使用即时调度器(同步执行)
    this.webTestClient = WebTestClient.bindToApplicationContext(context)
        .scheduler(Schedulers.immediate())
        .configureClient()
        .build();
  }

  @Test
  public void getConstants_Valid_Success()  {
    this.dataRepository.saveAndFlush(data);
    // 验证测试线程能查到数据
    assert !this.dataRepository.findAll().isEmpty();

    String result = this.webTestClient.get()
        .uri("/api/constant")
        .accept(MediaType.APPLICATION_JSON)
        .exchange()
        .expectStatus().isOk()
        .expectBody(String.class)
        .returnResult()
        .getResponseBody();

    assert result != null;
  }
}

关键注意事项

  • 避免在Controller中随意使用subscribeOn切换线程,除非业务明确需要异步处理,否则保持请求线程与业务逻辑线程一致。
  • 使用Schedulers.immediate()确保WebTestClient的请求处理在测试线程执行,这样就能读取到@Transactional注解下未提交的测试数据。
  • 保留@Transactional的默认行为(测试结束自动回滚),无需手动提交事务,确保测试的幂等性,避免数据残留。

内容的提问来源于stack exchange,提问作者Steven Kristian

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:56:29