如何为Spring WebFlux Router编写无Autowired Handler的JUnit单元测试
测试Spring WebFlux路由函数(非集成测试)
要测试这类RouterFunction端点,核心思路是手动Mock依赖的Handler、构建路由函数,再用WebTestClient发起请求验证,完全不需要依赖Spring上下文或Autowired注入。具体实现如下:
核心步骤
- Mock EntityHandler:用Mockito创建
EntityHandler的模拟实例,避免依赖真实业务实现。 - 构建路由函数:直接实例化
EntityRouter,调用其route方法传入Mock的Handler,得到待测试的路由规则。 - 绑定WebTestClient:将构建好的路由函数绑定到WebTestClient,用它模拟HTTP请求,验证路由匹配、Handler调用及响应结果。
完整测试代码示例
import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class EntityRouterTest { // 1. Mock依赖的EntityHandler private final EntityHandler mockHandler = Mockito.mock(EntityHandler.class); // 2. 手动构建路由函数 private final RouterFunction<?> router = new EntityRouter().route(mockHandler); // 3. 绑定路由到WebTestClient,用于模拟请求 private final WebTestClient webTestClient = WebTestClient.bindToRouterFunction(router).build(); @Test void getAllEntities_ShouldTriggerFindAll() { // 预设Mock Handler的返回结果 when(mockHandler.findAll(any())).thenReturn(Mono.just(ServerResponse.ok().build())); // 模拟GET请求 webTestClient.get() .uri("/getAllEntities") .accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk(); // 验证Handler的findAll方法被正确调用 verify(mockHandler).findAll(any()); } @Test void getEntityById_ShouldTriggerFindById() { String testId = "1001"; when(mockHandler.findById(any())).thenReturn(Mono.just(ServerResponse.ok().build())); webTestClient.get() .uri("/getEntity/{id}", testId) .accept(MediaType.APPLICATION_STREAM_JSON) .exchange() .expectStatus().isOk(); verify(mockHandler).findById(any()); } @Test void createEntity_ShouldTriggerSave() { // 假设存在Entity实体类 Entity testEntity = new Entity("测试实体"); when(mockHandler.save(any())).thenReturn(Mono.just(ServerResponse.ok().build())); webTestClient.post() .uri("/createEntity") .contentType(MediaType.APPLICATION_JSON) .bodyValue(testEntity) .exchange() .expectStatus().isOk(); verify(mockHandler).save(any()); } @Test void deleteEntity_ShouldTriggerDelete() { String testId = "1001"; when(mockHandler.delete(any())).thenReturn(Mono.just(ServerResponse.ok().build())); webTestClient.delete() .uri("/deleteEntity/{id}", testId) .accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk(); verify(mockHandler).delete(any()); } }
关键细节说明
- 整个测试是纯单元测试,完全脱离Spring容器,启动速度极快。
- 可以通过
WebTestClient验证路由的匹配规则(比如请求方法、路径、媒体类型是否符合预期)。 - 利用Mockito的
verify方法,确保路由与Handler的绑定逻辑正确,避免出现路由指向错误方法的问题。 - 如果需要验证响应体内容,可在
exchange()后添加.expectBody(...)方法,例如expectBodyList(Entity.class).hasSize(2)。
内容的提问来源于stack exchange,提问作者axnet
相关产品推荐
相关产品推荐

