Golang中为什么有一个测试用例失败?

Golang中为什么有一个测试用例失败? 我找到了问题所在

TL;DR 问题出在我执行函数的顺序上。

出于兴趣,我开始基于丹麦语词干提取算法实现一个词干提取器。

这是我的测试代码: https://github.com/kristiannissen/sturdy-tribble/blob/main/stemmer_test.go

这是实现代码: https://github.com/kristiannissen/sturdy-tribble/blob/main/stemmer.go

运行测试时,undouble 函数会失败,但不是每次都失败,只是部分失败,这让我无法理解。

示例:

Got undertrykk, want undertryk, test undertrykkelse

所以我在 undouble 函数内部添加了一个日志,以检查是否找到并处理了重复字符。结果显示它确实处理了所有情况。

func undouble(word string) string {
	chars := str.Split(word, "")

	if chars[len(chars)-2] == chars[len(chars)-1] {
        word = str.TrimSuffix(word, chars[len(chars)-1])
	    log.Println(word) // 添加的日志
    }
	return word
}

运行测试时的输出:

2021/03/18 07:00:55 indtræf 2021/03/18 07:00:55 indtræf 2021/03/18 07:00:55 undersåt 2021/03/18 07:00:55 undersåt 2021/03/18 07:00:55 undertryk 2021/03/18 07:00:55 undertryk 2021/03/18 07:00:55 undertryk 2021/03/18 07:00:55 undertryk 2021/03/18 07:00:55 undertryk 2021/03/18 07:00:55 undertryk 2021/03/18 07:00:55 undertryk

所有测试都处理了。

那么为什么我的测试仍然失败呢?


更多关于Golang中为什么有一个测试用例失败?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中为什么有一个测试用例失败?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


从你的描述和代码来看,问题很可能出在测试用例的执行顺序上。在Go中,测试默认是并发执行的,但同一个包内的测试函数执行顺序并不固定。你的undouble函数可能被多个测试用例共享,并且某个测试修改了共享状态,影响了后续测试的结果。

具体来说,你的stemmer_test.go中有多个测试函数(如TestUndoubleTestStemmer等),它们可能都调用了undouble函数。如果undouble函数依赖或修改了全局状态(比如全局变量),那么测试执行的顺序不同,就会导致结果不一致。

关键点分析:

  1. 并发测试问题:Go的go test默认会并发执行测试,但你可以通过t.Parallel()显式控制。你的测试文件没有使用t.Parallel(),所以测试是顺序执行的,但顺序仍不固定。
  2. 共享状态污染:检查undouble函数是否依赖包级变量(如全局变量或缓存)。如果某个测试修改了这些状态,后续测试可能得到意外结果。
  3. 测试数据交叉影响:你的测试数据(如testCases)可能在多个测试间共享,如果被意外修改,会导致失败。

示例调试步骤:

首先,在TestUndouble开头添加日志,确认测试执行顺序:

func TestUndouble(t *testing.T) {
    t.Log("Running TestUndouble") // 添加日志
    // ... 原有测试代码
}

然后运行测试并观察输出顺序:

go test -v

如果问题确实由执行顺序引起,可以尝试以下方案:

方案1:重置共享状态

在每个测试开始时,重置可能被修改的全局状态。例如,如果存在全局变量var cache map[string]string,在测试函数开头初始化:

func TestUndouble(t *testing.T) {
    cache = make(map[string]string) // 重置缓存
    // ... 测试代码
}

方案2:隔离测试数据

确保每个测试使用独立的数据副本。例如,避免直接修改原始测试数据切片:

func TestUndouble(t *testing.T) {
    tests := []struct{ input, expected string }{
        {"undertrykk", "undertryk"},
        // ... 其他用例
    }
    for _, tc := range tests {
        // 使用tc.input和tc.expected,而不是共享变量
    }
}

方案3:固定测试顺序

使用testing.Init或按字母顺序命名测试函数(如TestA_UndoubleTestB_Stemmer),但这不是推荐做法,因为Go鼓励测试独立性。

实际代码检查:

查看你的stemmer.go,如果存在类似以下全局变量,可能就是问题根源:

var (
    doubleChars = []string{"kk", "mm", /*...*/} // 共享数据
)

在测试中,如果某个测试修改了doubleChars,其他测试就会受到影响。

快速验证:

运行测试时指定顺序,观察是否总是同一个测试失败:

go test -v -count=1 -run TestUndouble  # 只运行TestUndouble
go test -v -count=1 -run TestStemmer   # 只运行TestStemmer

如果单独运行都通过,但一起运行就失败,基本可以确认是共享状态问题。

总结:

你的undouble函数本身逻辑正确,但测试失败是由于测试间的状态污染。建议检查包内全局变量,并在每个测试开始时清理状态。Go测试应保持独立,不依赖执行顺序。

回到顶部