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
更多关于Golang中为什么有一个测试用例失败?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
从你的描述和代码来看,问题很可能出在测试用例的执行顺序上。在Go中,测试默认是并发执行的,但同一个包内的测试函数执行顺序并不固定。你的undouble函数可能被多个测试用例共享,并且某个测试修改了共享状态,影响了后续测试的结果。
具体来说,你的stemmer_test.go中有多个测试函数(如TestUndouble、TestStemmer等),它们可能都调用了undouble函数。如果undouble函数依赖或修改了全局状态(比如全局变量),那么测试执行的顺序不同,就会导致结果不一致。
关键点分析:
- 并发测试问题:Go的
go test默认会并发执行测试,但你可以通过t.Parallel()显式控制。你的测试文件没有使用t.Parallel(),所以测试是顺序执行的,但顺序仍不固定。 - 共享状态污染:检查
undouble函数是否依赖包级变量(如全局变量或缓存)。如果某个测试修改了这些状态,后续测试可能得到意外结果。 - 测试数据交叉影响:你的测试数据(如
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_Undouble、TestB_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测试应保持独立,不依赖执行顺序。

