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

如何使用stretchr/testify正确断言decimal类型数值相等

问题原因

stretchr/testify的require.Equal默认基于反射做深度字段对比,不会主动调用类型自带的相等判断方法。常用的Go decimal库(shopspring/decimal)内部存储为「绝对值系数+10的指数」结构,你报错里的两个值:

  • 期望值:系数为6,指数为3 → 6 * 10^3 = 6000
  • 实际值:系数为6000,指数为0 → 6000 * 10^0 = 6000

二者数值完全相等,但内部字段值不同,反射对比自然会判定不通过。再加你混用了NewFromFloat和NewFromFloat32两种不同精度的构造方法,更容易触发这类内部表示不一致的问题。

正确断言方式

1. 直接配合decimal自带的Equal方法使用

调用decimal类型原生的Equal方法做数值相等判断,再用require.True断言结果为真即可:

func Test_example(t *testing.T) {
    t.Run("test if two decimals are equal", func(t *testing.T) {
        sum_amount := decimal.NewFromFloat(1000.00).Add(decimal.NewFromFloat(5000.00))
        // 精确场景推荐统一用NewFromString/NewFromInt构造值,避免浮点数精度问题
        expected := decimal.NewFromInt(6000)
        require.True(t, expected.Equal(sum_amount))
    })
}

2. 封装通用断言helper(推荐项目中使用)

如果测试里大量用到decimal相等断言,可以封装一个和testify原生断言用法一致的辅助函数,减少重复代码:

// RequireDecimalEqual 断言两个decimal数值逻辑相等
func RequireDecimalEqual(t *testing.T, expected, actual decimal.Decimal, msgAndArgs ...interface{}) {
    t.Helper() // 标记为helper函数,断言失败时会定位到实际调用的代码行,不会定位到工具函数内部
    require.True(t, expected.Equal(actual), append([]interface{}{"decimal values not equal"}, msgAndArgs...)...)
}

使用方式和原生require.Equal完全一致:

RequireDecimalEqual(t, decimal.NewFromInt(6000), sum_amount)
注意事项
  • 不要混用不同精度的浮点数构造函数(NewFromFloat/NewFromFloat32/NewFromFloat64),浮点数本身存在二进制表示精度误差,涉及金额、计量等精确场景,优先用NewFromString或NewFromInt构造decimal值,从根源避免精度偏差。
  • 不止decimal,所有自带自定义Equal判断逻辑的类型(比如部分时间类型、ORM自定义字段类型),都不建议直接用require.Equal做反射对比,优先用类型自带的相等判断方法配合require.True/assert.True使用。

内容的提问来源于stack exchange,提问作者Barry Michael Doyle

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 18:36:20