使用StepVerifier测试Groovy Spock时ProductService断言失败排查
解决Mono断言失败:获取到MonoJust而非Product实例的问题
核心问题分析
你直接对Mono<Product>容器对象调用getName(),但Mono是反应式流的包装类,只有触发订阅后才会执行逻辑并输出内部的Product实例。直接操作容器本身,自然会拿到MonoJust(Mono的具体实现类)而非实际业务对象。
正确的StepVerifier测试写法
使用expectNext或consumeNextWith时,必须通过verify()/verifyComplete()触发订阅,才能验证流中的数据。示例代码如下:
@Test void testSaveProduct() { // 构造测试数据 Product testProduct = new Product("测试商品"); // Mock Repository的save行为 when(productRepository.save(any(Product.class))).thenReturn(Mono.just(testProduct)); // 调用Service方法获取Mono流 Mono<Product> savedProductMono = productService.saveProduct(testProduct); // 用StepVerifier验证流 StepVerifier.create(savedProductMono) .consumeNextWith(product -> { // 在消费回调中对实际Product实例做断言 assertEquals("测试商品", product.getName()); }) .verifyComplete(); // 必须调用此方法触发订阅与验证逻辑 }
常见错误排查
- 遗漏
verify()/verifyComplete():这是StepVerifier执行的核心,没有此步骤,流不会被订阅,断言逻辑永远不会运行。 - 直接对Mono对象断言:比如写
assertEquals("测试商品", savedProductMono.getName()),这属于逻辑错误——Mono容器本身没有getName()方法。 - Repository Mock错误:检查mock语句是否正确返回
Mono<Product>,比如确认when(productRepository.save(...)).thenReturn(Mono.just(目标Product)),避免返回空Mono或错误类型。
临时同步获取方式(仅用于测试排查)
如果需要同步获取Product实例做临时验证,可使用block()方法(生产环境禁止使用):
Product savedProduct = savedProductMono.block(); assertEquals("测试商品", savedProduct.getName());
但反应式测试更推荐用StepVerifier,它能完整验证流的生命周期(如是否正常完成、是否抛出错误等)。
内容的提问来源于stack exchange,提问作者BreenDeen
相关产品推荐
相关产品推荐

