使用FluentAssertions校验小数点后字符位数的实现方法
FluentAssertions 校验数值小数点后位数的实现方案
方案1:decimal 类型直接使用内置 API
decimal 类型本身携带精度元数据,FluentAssertions 提供了内置的 HaveScale 方法可直接校验小数点后的位数:
- 校验小数点后恰好为指定位数:
decimal testedValue = 123.45m; // 校验通过 testedValue.Should().HaveScale(2); // 校验失败 testedValue.Should().HaveScale(3);
- 允许末尾省略 0 的场景,可以开启
ignoreTrailingZeros参数:
decimal testedValue = 123.4m; // 校验通过,123.4 视为等同于 123.40 testedValue.Should().HaveScale(2, ignoreTrailingZeros: true);
方案2:通用数值类型(double/float 等)的校验方案
浮点数类型没有内置的小数点位数校验方法,可以按需选择以下两种实现:
写法1:快速阈值校验
配合 BeApproximately 方法,通过精度阈值控制小数点位数,适合临时用例:
double testedValue = 123.45; // 校验2位小数,阈值设为保留n位小数对应精度的一半,避免四舍五入边界问题 testedValue.Should().BeApproximately(Math.Round(testedValue, 2), 0.005);
写法2:自定义通用扩展方法
适合需要频繁校验小数点位数的场景,封装后可全局复用:
using System.Globalization; using FluentAssertions; using FluentAssertions.Numeric; public static class NumericAssertionExtensions { public static AndConstraint<NumericAssertions<T>> HaveDecimalPlaces<T>( this NumericAssertions<T> assertions, int expectedDecimalPlaces, string because = "", params object[] becauseArgs) where T : struct, IComparable, IComparable<T>, IEquatable<T>, IConvertible { double value = assertions.Subject.ToDouble(CultureInfo.InvariantCulture); double scaledValue = value * Math.Pow(10, expectedDecimalPlaces); // 加入极小容差,避免浮点数二进制存储误差导致的偶发失败 bool isMatch = Math.Abs(scaledValue - Math.Round(scaledValue)) < 1e-9; Execute.Assertion .ForCondition(isMatch) .BecauseOf(because, becauseArgs) .FailWith("Expected {context:value} to have {0} decimal places, but found {1}", expectedDecimalPlaces, value); return new AndConstraint<NumericAssertions<T>>(assertions); } }
调用方式非常简洁:
// 校验通过 123.45d.Should().HaveDecimalPlaces(2); // 校验失败 123.456d.Should().HaveDecimalPlaces(2);
最佳实践建议
- 金融、计量等对精度要求高的场景优先使用 decimal 类型,直接调用内置
HaveScale方法即可,无需额外编码 - 浮点数校验时必须设置合理的容差,避免二进制浮点精度误差导致测试偶发失败
- 项目中如果有大量小数点位数校验需求,优先封装通用扩展方法,统一校验逻辑
内容的提问来源于stack exchange,提问作者runnerpaul
相关产品推荐
相关产品推荐

