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

如何用StepVerifier验证WebFlux中ProductService返回的单个产品数据

如何用StepVerifier验证Flux中的复杂ProductData对象

当需要验证Flux返回的复杂对象时,直接用equals全量对比容易因嵌套属性、动态字段(如时间戳)失效,推荐以下几种方案:

方案1:验证关键属性(最常用)

通过StepVerifier.consumeNextWith()方法,在回调里逐个校验核心业务属性,无需全量对比。

示例测试代码:

import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import java.time.LocalDateTime;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;

class ProductServiceTest {

    private ProductRepository productRepository;
    private ProductService productService;

    // 初始化测试环境
    public ProductServiceTest() {
        productRepository = Mockito.mock(ProductRepository.class);
        productService = new ProductService(productRepository);
    }

    @Test
    void findAll_ShouldReturnValidProducts() {
        // 构造测试用的ProductData
        ProductData testProduct = buildTestProduct();
        Mockito.when(productRepository.findAll()).thenReturn(Flux.just(testProduct));

        Flux<ProductData> productFlux = productService.findAll();

        StepVerifier.create(productFlux)
                .consumeNextWith(product -> {
                    // 校验Order层属性
                    assertNotNull(product.getOrder());
                    assertEquals("ORD-001", product.getOrder().getOrderId());
                    assertEquals("john_doe", product.getOrder().getOrderedBy());

                    // 校验OrderItem列表
                    List<ProductData.OrderItem> items = product.getOrder().getOrderItems();
                    assertFalse(items.isEmpty());
                    assertEquals(1, items.size());

                    // 校验单个OrderItem属性
                    ProductData.OrderItem item = items.get(0);
                    assertEquals("ITEM-LAP-001", item.getItemCode());
                    assertEquals("Gaming Laptop", item.getName());
                    assertEquals(2, item.getQuantity());

                    // 嵌套校验ItemGroup属性
                    ProductData.ItemGroup group = item.getGroup();
                    assertEquals("Electronics", group.getCategory());
                    assertEquals("WH-NY-003", group.getWarehouseID());
                    assertEquals("Shelf B-5", group.getWarehoueLocation());
                })
                .verifyComplete();
    }

    // 辅助方法:构造测试数据
    private ProductData buildTestProduct() {
        ProductData.ItemGroup itemGroup = new ProductData.ItemGroup();
        itemGroup.setCategory("Electronics");
        itemGroup.setWarehouseID("WH-NY-003");
        itemGroup.setWarehoueLocation("Shelf B-5");

        ProductData.OrderItem orderItem = new ProductData.OrderItem();
        orderItem.setItemCode("ITEM-LAP-001");
        orderItem.setName("Gaming Laptop");
        orderItem.setQuantity(2);
        orderItem.setQuantityOnHold(0);
        orderItem.setGroup(itemGroup);

        ProductData.Order order = new ProductData.Order();
        order.setOrderId("ORD-001");
        order.setOrderedBy("john_doe");
        order.setOrderDate(LocalDateTime.now());
        order.setOrderItems(List.of(orderItem));

        ProductData productData = new ProductData();
        productData.setOrder(order); // 假设ProductData类有对应的Order属性
        return productData;
    }
}

方案2:使用Hamcrest匹配器简化断言

如果习惯用Hamcrest语法,可以结合assertThat做更灵活的嵌套断言:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

// 在consumeNextWith回调中替换断言逻辑
.consumeNextWith(product -> {
    assertThat(product.getOrder().getOrderId(), equalTo("ORD-001"));
    assertThat(product.getOrder().getOrderItems(), hasSize(1));
    assertThat(product.getOrder().getOrderItems().get(0).getGroup().getCategory(), equalTo("Electronics"));
})

方案3:重写equals/hashCode(需修改实体类)

如果允许修改ProductData及其内部类,可以用Lombok的@EqualsAndHashCode注解自动生成仅对比关键属性的方法,之后直接用expectNext()断言:

// 修改实体类,添加注解
import lombok.EqualsAndHashCode;

@EqualsAndHashCode
public class ProductData {
  
  @EqualsAndHashCode
  static class Order {
    // 属性不变
  }
  
  @EqualsAndHashCode
  static class OrderItem {
    // 属性不变
  }
  
  @EqualsAndHashCode
  static class ItemGroup{
    // 属性不变
  }
}

// 测试代码中直接断言
StepVerifier.create(productFlux)
        .expectNext(testProduct)
        .verifyComplete();

注意事项

  • 优先选择方案1,避免因非业务属性(如自动生成的时间戳)导致断言失败;
  • 若实体类无法修改,绝对不要强行用全量equals,专注校验影响业务逻辑的核心字段即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 06:35:29