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

使用FluentAssertions比较System.Data对象时的类型转换问题

问题

我在用FluentAssertions校验两个System.Data.DataColumnCollection中的DataColumn等价性时遇到了问题。

原测试代码:

Columns.OfType<DataColumn>().Should().BeEquivalentTo(Columns.OfType<DataColumn>(), options => options
    .Using<double>(ctx => ((double)ctx.Subject).Should().BeApproximately((double)ctx.Expectation, 0.000000001F))
    .WhenTypeIs<double>());

运行后抛出异常:

Expected property Columns.OfType()[8].DataType to be System.Decimal, but found System.Double.

原因是预期值从base64反序列化而来,无法干预这个过程,导致部分浮点数对应的DataColumn.DataType被转为decimal,和实际的double类型不匹配。我尝试同时处理decimal和double的数值比较,但问题仍未解决:

Columns.OfType<DataColumn>()
       .Should()
       .BeEquivalentTo(Columns.OfType<DataColumn>(), options => options                                                                                                      
             .RespectingDeclaredTypes()                                  
             .Using<decimal>(ctx => (decimal.ToDouble(ctx.Subject)).Should().BeApproximately(decimal.ToDouble(ctx.Expectation), 0.000000001F))
             .WhenTypeIs<decimal>()
             .Using<double>(ctx => ((double)ctx.Subject).Should().BeApproximately((double)ctx.Expectation, 0.000000001F))
             .WhenTypeIs<double>());

请问有没有办法在比较时动态覆写逻辑(比如提前转换类型)来避免这个异常?

解决方案

核心问题是你只处理了数值类型的近似比较,但没解决**DataColumn.DataType属性的类型不匹配**问题——FluentAssertions默认会严格校验属性类型,所以需要针对DataType单独配置规则,同时调整类型检查策略。

方案1:自定义DataType比较规则(推荐)

通过UsingForMember为DataType属性指定自定义匹配逻辑,允许double和decimal互相视为等价,同时保留其他属性的正常校验:

Columns.OfType<DataColumn>().Should().BeEquivalentTo(Columns.OfType<DataColumn>(), options => options
    // 针对DataType属性设置特殊比较规则
    .UsingForMember(col => col.DataType, config => config
        .CompareWith((subjectType, expectationType) => 
            // 允许double和decimal互相匹配,其他类型严格相等
            (subjectType == typeof(double) && expectationType == typeof(decimal)) ||
            (subjectType == typeof(decimal) && expectationType == typeof(double)) ||
            subjectType == expectationType))
    // 关闭严格类型声明检查,确保兼容数值类型能被正常比较
    .RespectingDeclaredTypes(false)
    // 对double类型做近似精度校验
    .Using<double>(ctx => ((double)ctx.Subject).Should().BeApproximately((double)ctx.Expectation, 1e-9))
        .WhenTypeIs<double>()
    // 将decimal转为double后做近似精度校验
    .Using<decimal>(ctx => decimal.ToDouble(ctx.Subject).Should().BeApproximately(decimal.ToDouble(ctx.Expectation), 1e-9))
        .WhenTypeIs<decimal>());

关键点解释:

  • UsingForMember处理DataType:直接针对DataColumn.DataType属性定制匹配逻辑,从根源解决类型不匹配的断言错误。
  • 关闭RespectingDeclaredTypes:默认情况下FluentAssertions允许兼容类型的比较,但显式关闭严格类型检查可以避免潜在的类型校验冲突。
  • 数值近似校验:分别对double和decimal类型的数值做转换后校验,满足浮点精度要求。

方案2:预处理预期列(如果允许操作预期实例)

如果可以在测试中修改反序列化后的预期列,直接将DataType为decimal的列转为double,就能彻底避免类型匹配问题:

// 预处理预期列:把decimal类型的列转为double
var adjustedExpectedColumns = expectedColumns.OfType<DataColumn>()
    .Select(col => 
    {
        if (col.DataType != typeof(decimal)) return col;
        
        var newCol = new DataColumn(col.ColumnName, typeof(double));
        // 复制原列的关键属性(根据你的需求补充)
        newCol.AllowDBNull = col.AllowDBNull;
        newCol.DefaultValue = col.DefaultValue != DBNull.Value 
            ? decimal.ToDouble((decimal)col.DefaultValue) 
            : DBNull.Value;
        return newCol;
    });

// 执行等价性校验
actualColumns.OfType<DataColumn>().Should().BeEquivalentTo(adjustedExpectedColumns, options => options
    .Using<double>(ctx => ((double)ctx.Subject).Should().BeApproximately((double)ctx.Expectation, 1e-9))
    .WhenTypeIs<double>());

这种方案更直接,但需要你有权限修改预期列的实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 11:20:32