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

AssertJ中如何使用RecursiveComparisonConfiguration实现递归断言?

使用AssertJ的RecursiveComparisonConfiguration优化实体断言逻辑

问题背景

现有两个实体类HospitalDailyCashProductDetails和HospitalDailyCashCoversDetailsUI,部分属性键名一致但存在格式差异,实体结构如下:

HospitalDailyCashProductDetails(productId=4148, productCode=4148, premiumAmount=600, productDescription=(Hospital Daily Cash Cover), productName=Group Safeguard Insurance, sumInsured=₹ 750.00 per day for up to 30 days, validityPeriod=12 Months, dateOfIssuance=04/03/2024)

HospitalDailyCashCoversDetailsUI(premiumAmount=₹600.00, sumInsured=₹ 750.00 per day for up to 30 days, validityPeriod=12 Months, dateOfIssuance=04/03/2024)

原断言逻辑需要逐个属性处理格式差异并单独编写断言,代码如下:

HospitalDailyCashProductDetails hospitalDailyCashProductDetails = testContext.getContext(ScenarioContextKey.HOSPITAL_DAILY_CASH_COVERS);
HospitalDailyCashCoversDetailsUI hospitalDailyCashCoversDetailsUI = hospitalDailyCashCovers.getHospitalDailyCashCoversDetailsUI();

String strExpectedPremiumAmount = hospitalDailyCashProductDetails.getPremiumAmount();
String strActualPremiumAmount = hospitalDailyCashCoversDetailsUI.getPremiumAmount();
testContext.softAssertion().assertThat(strActualPremiumAmount).withFailMessage("Expected Premium Amount is %s, but was %s", strExpectedPremiumAmount, strActualPremiumAmount).contains(strExpectedPremiumAmount);

String strExpectedSumInsured = hospitalDailyCashProductDetails.getSumInsured().replaceAll("₹","₹");
String strActualSumInsured = hospitalDailyCashCoversDetailsUI.getSumInsured();
testContext.softAssertion().assertThat(strActualSumInsured).withFailMessage("Expected Sum Assured is %s, but was %s", strExpectedSumInsured, strActualSumInsured).isEqualTo(strExpectedSumInsured);

String strExpectedValidityPeriod = hospitalDailyCashProductDetails.getValidityPeriod();
String strActualValidityPeriod = hospitalDailyCashCoversDetailsUI.getValidityPeriod();
testContext.softAssertion().assertThat(strActualValidityPeriod).withFailMessage("Expected Validity Period is %s, but was %s", strExpectedValidityPeriod, strActualValidityPeriod).isEqualTo(strExpectedValidityPeriod);

String strExpectedDateOfIssuance = hospitalDailyCashProductDetails.getDateOfIssuance();
String strActualDateOfIssuance = hospitalDailyCashCoversDetailsUI.getDateOfIssuance();
testContext.softAssertion().assertThat(strActualDateOfIssuance).withFailMessage("Expected Date Of Insurance is %s, but was %s", strExpectedDateOfIssuance, strActualDateOfIssuance).isEqualTo(strExpectedDateOfIssuance);

现需使用AssertJ的RecursiveComparisonConfiguration优化上述断言逻辑,同时保留自定义的testContext.softAssertion()软断言机制。

优化方案

1. 构建递归比较配置

针对属性的格式差异,为特定字段指定自定义比较规则,同时忽略两个实体中不匹配的字段:

  • sumInsured:将预期值中的HTML实体₹转换为货币符号₹后再与实际值比较
  • premiumAmount:提取实际值中的数字部分,判断是否包含预期的纯数字字符串
  • 忽略HospitalDailyCashProductDetails中存在但HospitalDailyCashCoversDetailsUI没有的属性

2. 整合软断言执行递归比较

将配置好的递归比较逻辑整合到自定义软断言中,一次性完成所有匹配属性的断言。

具体代码实现

HospitalDailyCashProductDetails hospitalDailyCashProductDetails = testContext.getContext(ScenarioContextKey.HOSPITAL_DAILY_CASH_COVERS);
HospitalDailyCashCoversDetailsUI hospitalDailyCashCoversDetailsUI = hospitalDailyCashCovers.getHospitalDailyCashCoversDetailsUI();

// 构建递归比较配置
RecursiveComparisonConfiguration config = RecursiveComparisonConfiguration.builder()
        // 处理sumInsured属性的货币符号差异
        .withEqualsForFields((expected, actual) -> {
            String convertedExpected = ((String) expected).replaceAll("₹", "₹");
            return convertedExpected.equals(actual);
        }, "sumInsured")
        // 处理premiumAmount的格式差异:验证实际值包含预期数字
        .withEqualsForFields((expected, actual) -> {
            String expectedNum = (String) expected;
            String actualCleaned = ((String) actual).replaceAll("[₹.]", "").trim();
            return actualCleaned.contains(expectedNum);
        }, "premiumAmount")
        // 忽略两个实体中不匹配的字段
        .withIgnoredFields("productId", "productCode", "productDescription", "productName")
        .build();

// 结合自定义软断言执行递归比较
testContext.softAssertion().assertThat(hospitalDailyCashCoversDetailsUI)
        .usingRecursiveComparison(config)
        .withFailMessage("实体属性不匹配,预期: %s,实际: %s", hospitalDailyCashProductDetails, hospitalDailyCashCoversDetailsUI)
        .isEqualTo(hospitalDailyCashProductDetails);

关键说明

  • 递归比较会自动遍历所有匹配的属性,无需逐个编写断言,大幅简化代码
  • withEqualsForFields针对特定属性的格式差异定制比较逻辑,精准处理字段匹配规则
  • withIgnoredFields避免因实体结构不一致导致的比较错误
  • 保留自定义软断言机制,所有属性的断言失败都会被收集,不会中断测试执行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 15:24:52