如何在Go单元测试中比较包含NaN元素的切片?
解决Go单元测试中含NaN的切片断言问题
在使用testify/assert包断言包含NaN的float64切片时,由于NaN不等于自身的特性,会出现预期和实际值看起来一致但断言失败的情况:
import ( "math" "github.com/stretchr/testify/assert" ) func CallMe() []float64 { return []float64{math.NaN()} } func TestCallMe(t *testing.T) { assert.Equal(t, []float64{math.NaN()}, CallMe()) }
运行后错误输出:
Error: Not equal: expected: []float64{NaN} actual : []float64{NaN} Diff: Test: TestCallMe
解决方案:自定义复用的断言函数
不用放弃testify的简洁性,你可以封装一个专门处理float64切片(含NaN)的断言函数,既避免冗长的逐元素检查,又保留清晰的错误输出:
import ( "math" "github.com/stretchr/testify/assert" ) // assertFloat64SliceEqual 断言两个float64切片相等,处理NaN的特殊情况 func assertFloat64SliceEqual(t assert.TestingT, expected, actual []float64, msgAndArgs ...interface{}) bool { // 先检查长度是否一致,不一致直接用原Equal输出差异 if len(expected) != len(actual) { return assert.Equal(t, expected, actual, msgAndArgs...) } // 逐元素检查,NaN和NaN视为相等 for i := range expected { expVal := expected[i] actVal := actual[i] if math.IsNaN(expVal) && math.IsNaN(actVal) { continue } if expVal != actVal { // 元素不相等时,用原Equal输出完整切片差异 return assert.Equal(t, expected, actual, msgAndArgs...) } } return true } func TestCallMe(t *testing.T) { // 测试代码依然简洁 assertFloat64SliceEqual(t, []float64{math.NaN()}, CallMe()) }
优势说明
- 测试代码保持一行的简洁性,无需在测试函数中写循环逻辑
- 当断言失败时,依然会输出
testify风格的清晰差异对比,便于定位问题 - 自定义函数可在所有需要检查含NaN的float64切片的测试中复用,减少重复代码
内容的提问来源于stack exchange,提问作者egor10_4
相关产品推荐
相关产品推荐

