使用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
相关产品推荐
相关产品推荐

