浮点数相等断言必须用容差,因IEEE 754导致0.1+0.2≠0.3是正常现象;应使用assert.InDelta或自定义函数(含NaN/Inf检查)而非assert.Equal,结构体比较需逐字段处理或序列化。

浮点数相等断言必须用容差,assert.Equal 会直接失败
Go 中 float64 遵循 IEEE 754,0.1 + 0.2 != 0.3 是正常现象,不是 bug。用 assert.Equal(t, got, want) 比较两个浮点数,哪怕视觉上“一样”,只要内存中二进制表示有微小差异(比如第16位尾数不同),断言就失败。
Testify 的 assert.InDelta 是专为此设计的:
-
assert.InDelta(t, got, want, epsilon)判断math.Abs(got - want) -
epsilon不是固定值:业务逻辑常用1e-9,科学计算可压到1e-15 - 别设
1e-16或更小——可能比 float64 机器精度还严,反而让本该通过的测试挂掉
测试前必须排除 NaN 和 Inf,否则 math.Abs(a-b) 永远不成立
如果浮点数来自用户输入、JSON 解析或未防护的数学运算(如 math.Sqrt(-1)、1.0/0.0),a 或 b 可能是 NaN 或 +Inf/-Inf。此时 math.Abs(a - b) 返回 NaN,整个条件恒为 false,且不报错,极易漏判。
正确做法是显式检查:
- 用
!math.IsNaN(a) && !math.IsNaN(b)排除非法值 - 用
!math.IsInf(a, 0) && !math.IsInf(b, 0)同时捕获正负无穷 - 若只关心正无穷,改用
math.IsInf(x, +1)
自定义断言函数比硬写 t.Errorf 更安全、复用性更高
在多个测试文件里反复写 if math.Abs(got-want) > eps { t.Errorf(...) } 容易出错、难维护。封装成函数能统一逻辑、避免遗漏 NaN/Inf 检查。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
例如:
func assertFloat64Equal(t *testing.T, want, got, eps float64) {
t.Helper()
if math.IsNaN(want) || math.IsNaN(got) {
t.Fatalf("NaN not allowed: want=%v, got=%v", want, got)
}
if math.IsInf(want, 0) || math.IsInf(got, 0) {
t.Fatalf("Inf not allowed: want=%v, got=%v", want, got)
}
if math.Abs(got-want) > eps {
t.Errorf("float64 mismatch: want %v, got %v (delta > %v)", want, got, eps)
}
}
-
t.Helper()让错误行号指向调用处,不是函数内部 - 把容差
eps作为参数传入,不同场景可灵活指定(比如金融用1e-2,几何计算用1e-9) - 比第三方库轻量,无依赖,适合对引入外部断言库有顾虑的项目
结构体含 float64 字段时,别用 assert.Equal 直接比整个 struct
如果结构体里有 float64 字段,用 assert.Equal(t, wantStruct, gotStruct) 仍会触发底层 == 比较,精度问题照旧。更糟的是:结构体含未导出字段时,assert.Equal 无法访问,直接 panic。
稳妥做法是:
- 逐字段比:对 float 字段用
assert.InDelta,其余字段用assert.Equal - 或序列化后比字符串:
assert.JSONEq(t, marshal(want), marshal(got)),前提是字段都可 JSON 序列化且顺序无关 - 避免用
reflect.DeepEqual—— 它对 float64 仍是严格==,且不处理 NaN/Inf
实际误差往往藏在链路深处:比如从 JSON 解析字符串时,json.Unmarshal 调用 strconv.ParseFloat,已做一次精度截断;后续再参与运算,误差就叠加了。真要验证精度,得从源头控制——要么用 string 或 int64 存原始值,要么全程用 shopspring/decimal。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










