WebFlux单元测试问题:调用未进入.map与.flatMap处理逻辑
WebFlux Mono链未执行的单元测试问题
我正在为WebFlux中的calculate方法编写单元测试,业务代码如下:
@Override public Mono<SearchSessionAndETAResponse> calculate(DTO sessionRequest) throws ExecutionException, InterruptedException { List<GeospatialData> dataFromRedis = getDataFromRedis(sessionRequest.getSessionId()); return Mono.just(dataFromRedis) .map(data -> { System.out.println("data::"+data); return "entityIdentifiers"; }) .flatMap(entityIdentifiers -> { System.out.println("entityIdentifiers::"+entityIdentifiers); return etaService.entitiesEta("entityIdentifiers"); }) .map(wayPointRoute -> { return searchSessionAndETAResponse; }); }
对应的测试用例代码:
@ExtendWith(MockitoExtension.class) public class BroadCastingServiceImplTest { @InjectMocks private BroadCastingServiceImpl broadCastingService; @Mock private EtaService etaService; @BeforeEach void setUp() { closeable = MockitoAnnotations.openMocks(this); } @AfterEach void tearDown() throws Exception { closeable.close(); } @Test @DisplayName("Given a valid request, when SearchSession and calculate eta is called, it should search Broadcasting session and return eta") void givenValidRequest_whenSearchSessionAndCalculateEta_shouldReturnBroadCastingResponseDTO() throws ExecutionException, InterruptedException, IOException { // GIVEN UUID sessionId = UUID.randomUUID(); DTO searchSessionAndCalculateETA = new DTO(); searchSessionAndCalculateETA.setSessionId(sessionId.toString()); searchSessionAndCalculateETA.setWaypoints(List.of("waypointsDTO", "waypointsDTO2")); given(etaService.entitiesEta("entitiesEtaRequestDTO")).willReturn(Mono.just(List.of("entitiesEtaResponseDTO"))); // WHEN Mono<SearchSessionAndETAResponse> result = broadCastingService.searchSessionAndCalculateETA(searchSessionAndCalculateETA); } }
问题:运行测试用例时,尽管dataFromRedis不为空,但调用并未进入Mono链中的.map、.flatMap及后续.map处理逻辑,请问我遗漏了什么关键步骤?
问题原因与解决方法
- Mono是惰性执行的:WebFlux的响应式类型(Mono/Flux)遵循惰性求值原则,只有当被订阅时,整个链式调用才会实际执行。你当前的测试仅创建了Mono对象,但未触发订阅操作,导致链中的
.map、.flatMap等逻辑完全没启动。 - 测试需触发订阅或使用StepVerifier:单元测试中推荐使用
StepVerifier(来自spring-boot-test依赖)来验证响应式流的行为,它会自动触发订阅,并能断言流的输出、完成状态等。如果不想用StepVerifier,也可以调用result.block()手动阻塞触发订阅,但这种方式不符合响应式编程的测试规范,仅作临时调试用。 - 额外问题:Mock参数不匹配:业务代码中调用
etaService.entitiesEta("entityIdentifiers")时传入的是固定字符串"entityIdentifiers",但测试中Mock的却是etaService.entitiesEta("entitiesEtaRequestDTO"),参数不匹配会导致Mock失效,即使触发订阅,这一步也会返回空或报错。
修改后的测试代码示例:
@Test @DisplayName("Given a valid request, when SearchSession and calculate eta is called, it should search Broadcasting session and return eta") void givenValidRequest_whenSearchSessionAndCalculateEta_shouldReturnBroadCastingResponseDTO() throws ExecutionException, InterruptedException, IOException { // GIVEN UUID sessionId = UUID.randomUUID(); DTO searchSessionAndCalculateETA = new DTO(); searchSessionAndCalculateETA.setSessionId(sessionId.toString()); searchSessionAndCalculateETA.setWaypoints(List.of("waypointsDTO", "waypointsDTO2")); // 确保Mock参数与业务代码一致 given(etaService.entitiesEta("entityIdentifiers")).willReturn(Mono.just(List.of("entitiesEtaResponseDTO"))); // 初始化预期返回的响应对象 SearchSessionAndETAResponse expectedResponse = new SearchSessionAndETAResponse(); // WHEN & THEN:用StepVerifier触发订阅并验证结果 StepVerifier.create(broadCastingService.searchSessionAndCalculateETA(searchSessionAndCalculateETA)) .expectNext(expectedResponse) .verifyComplete(); }
内容的提问来源于stack exchange,提问作者Divya Singh
相关产品推荐
相关产品推荐

