Golang程序测试指南与最佳实践

Golang程序测试指南与最佳实践

func TestAvg2(t *testing.T) {
	type test struct {
		data   []float64
		answer float64
	}

	tests := []test{
		test{[]float64{2, 2}, 2.00},
		test{[]float64{4, 4}, 4.00},
		test{[]float64{3, 3, 4}, 3.33},
		test{[]float64{3, 3, 5}, 3.67},
		test{[]float64{5, 5, 5}, 5.00},
		test{[]float64{-10, 10, 10, 11}, 5.25},
	}

	for _, v := range tests {
		x := Avg(v.data...)
		str := fmt.Sprintf("%.2f", x)
		fl, _ := strconv.ParseFloat(str, 64)
		if x != v.answer {
			t.Error("Expected", v.answer, "got", fl)
		}
	}
}

结果: table_test.go:29: Expected 3.33 got 3.33 table_test.go:29: Expected 3.67 got 3.67

哪里出错了?


更多关于Golang程序测试指南与最佳实践的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

舍入误差。这是浮点数众所周知的特性。

对于浮点数,通常检查两个值之间差值的绝对值是否小于或等于某个阈值,如果差值足够小,则认为它们相等。

更多关于Golang程序测试指南与最佳实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题出在浮点数精度比较上。使用 != 直接比较浮点数会导致精度问题,即使显示值相同,底层二进制表示可能不同。

以下是修复后的测试代码:

func TestAvg2(t *testing.T) {
    type test struct {
        data   []float64
        answer float64
    }

    tests := []test{
        {[]float64{2, 2}, 2.00},
        {[]float64{4, 4}, 4.00},
        {[]float64{3, 3, 4}, 3.33},
        {[]float64{3, 3, 5}, 3.67},
        {[]float64{5, 5, 5}, 5.00},
        {[]float64{-10, 10, 10, 11}, 5.25},
    }

    for _, v := range tests {
        x := Avg(v.data...)
        // 使用容差比较浮点数
        if math.Abs(x-v.answer) > 0.01 {
            t.Errorf("Expected %.2f, got %.2f", v.answer, x)
        }
    }
}

或者使用 cmp.Diff 进行更精确的比较:

import "github.com/google/go-cmp/cmp"

func TestAvg2(t *testing.T) {
    type test struct {
        data   []float64
        answer float64
    }

    tests := []test{
        {[]float64{2, 2}, 2.00},
        {[]float64{4, 4}, 4.00},
        {[]float64{3, 3, 4}, 3.33},
        {[]float64{3, 3, 5}, 3.67},
        {[]float64{5, 5, 5}, 5.00},
        {[]float64{-10, 10, 10, 11}, 5.25},
    }

    for _, v := range tests {
        x := Avg(v.data...)
        // 使用cmp.Comparer定义浮点数比较容差
        opt := cmp.Comparer(func(x, y float64) bool {
            return math.Abs(x-y) <= 0.01
        })
        
        if diff := cmp.Diff(v.answer, x, opt); diff != "" {
            t.Errorf("Mismatch (-want +got):\n%s", diff)
        }
    }
}

对于测试表格,推荐使用子测试:

func TestAvg2(t *testing.T) {
    tests := []struct {
        name   string
        data   []float64
        want   float64
    }{
        {"two equal numbers", []float64{2, 2}, 2.00},
        {"another two equal", []float64{4, 4}, 4.00},
        {"three numbers with decimal", []float64{3, 3, 4}, 3.33},
        {"three numbers with different decimal", []float64{3, 3, 5}, 3.67},
        {"all same numbers", []float64{5, 5, 5}, 5.00},
        {"mixed positive negative", []float64{-10, 10, 10, 11}, 5.25},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := Avg(tt.data...)
            if math.Abs(got-tt.want) > 0.01 {
                t.Errorf("Avg() = %.2f, want %.2f", got, tt.want)
            }
        })
    }
}

浮点数比较应该始终使用容差(epsilon)值,而不是直接相等比较。

回到顶部