Spring Boot WebFlux测试中Clock Mock引发空指针问题求助
修复WebFluxTest中Mock Clock导致的NullPointerException问题
你遇到的空指针问题,根源在于通过Mockito静态mock Clock类的方式干扰了Spring WebFlux内部组件的初始化。当调用webTestClient.mutate().build()时,Spring会重新构建WebHttpHandlerAdapter并创建InMemoryWebSessionStore,此时你mock的Clock.systemUTC()返回的是一个未完全实现的Spy Clock实例——由于Clock是接口,直接spy接口无法生成完整的实现逻辑,导致Spring内部调用Clock方法时触发空指针。
这种静态mock的侵入性极强,会影响所有依赖Clock.systemUTC()的代码(包括Spring框架自身组件),这也是不用WebTestClient的测试能正常运行,但使用后报错的核心原因。
修复方案:用Spring依赖注入替换静态Mock
正确的做法是利用Spring的Bean替换机制,提供自定义的Clock Bean,让所有Spring管理的组件(包括业务代码和WebFlux内部会话存储)都使用你指定的Clock,彻底避免静态Mock的副作用。
修改后的测试代码:
@ExtendWith(SpringExtension.class) @WebFluxTest(controllers = MyController.class) @Import({MyController.class}) public class Test implements WebTestClientConfigurable { @Autowired private MyController myController; @Autowired private WebTestClient webTestClient; // 固定测试时间(可根据需求调整) private static final Instant TEST_NOW = Instant.ofEpochMilli(System.currentTimeMillis()); // 自定义Clock Bean,覆盖默认系统Clock @TestConfiguration static class TestClockConfig { @Bean public Clock clock() { // 返回固定时间的Clock实例 return Clock.fixed(TEST_NOW, ZoneOffset.UTC); } } @org.junit.jupiter.api.Test void test() { configure(webTestClient) .post() .uri("/test") .exchange() .expectStatus() .is2xxSuccessful(); } }
动态调整时间的扩展方案:
如果需要在测试中动态修改时间,可以给Clock Bean增加可变性,比如用原子引用包装时间:
@TestConfiguration static class TestClockConfig { private final AtomicReference<Instant> currentInstant = new AtomicReference<>(TEST_NOW); @Bean public Clock clock() { return new Clock() { @Override public Instant instant() { return currentInstant.get(); } @Override public ZoneId getZone() { return ZoneOffset.UTC; } @Override public Clock withZone(ZoneId zone) { return Clock.fixed(currentInstant.get(), zone); } }; } // 提供方法动态更新时间 public void setCurrentInstant(Instant newInstant) { currentInstant.set(newInstant); } }
在测试中注入TestClockConfig,调用setCurrentInstant()即可随时调整时间。
内容的提问来源于stack exchange,提问作者marie
相关产品推荐
相关产品推荐

