在我们的特殊情况下,我们使用T.RUN进行了许多嵌套子测验,并且可以并行运行的测试,但是总的来说,我们发现测试套件可能会失败而不会单独的测试失败。
在我上面的示例中,如果您向后搜索“失败”,您似乎有点像:--- FAIL: TestVariousQueries/7-node (482.60s)
--- PASS: TestVariousQueries/7-node/0-G
...
在哪里表明最高级测试失败了,但是所有子测验似乎都通过,并且没有其他输出或消息表明测试为什么失败。
有时它看起来像这样,这给出了更多的线索
...
=== RUN TestVariousQueries/7-node/8-Count(All())
FAIL github.com/pilosa/pilosa/v2 394.988s
FAIL
在这种情况下,似乎上次测试开始了,但是某种程度上没有输出失败(我们希望为该特定的测试获得一条线,而不是仅仅是软件包级别失败。
哪些情况会导致这种情况发生?怎么会调试?
我不确定我是否对可能导致的原因有完整的核算,但是当系统耗尽内存并且OOM杀手杀死测试过程时,我肯定已经看到它发生了。至少在Linux上,您可以在测试运行以查看内核日志时运行
--- FAIL
或类似
dmesg
。如果您看到类似的东西:
tail -f /var/log/syslog
您可以确定由于记忆不足而被杀死的测试。 这可能发生的其他方法是,如果测试(或正在测试)调用中的某些代码。在这种情况下,根据GO版本和操作系统,您可能会看到一个状态代码,或者您可能只是在原始问题中的示例中看到失败消息。
总的来说,如果您从测试中看到这样的输出,似乎是一个很好的赌注,即导致测试过程退出,这会导致测试跑步者(
哪些情况会导致这种情况发生?您使用
os.Exit
(或go test
t.Fail()
在子测验之外,它将重现您要观察的内容:所有子测验通过,但总体测试失败而没有输出。示例Https://go.dev/play/p/ooeq_migv1l:
t.FailNow()
t.Fail()
在其他任何人都偶然发现这个问题的情况下 - 确保注意您的过程内存使用情况。 我将以下登录注入了我的测试中,从未见过超过100 MB的生长 - 这使我感到困惑。 然后,我运行了linux/unix命令“ top”,并通过内存(shift m)排序 - 我的过程爬到4千兆字节!
func TestVariousQueries(t *testing.T) {
t.Run("7-node", func(t *testing.T) {
t.Run("0-G", func(t *testing.T) { return })
t.Run("1-G", func(t *testing.T) { return })
t.Run("2-G", func(t *testing.T) { return })
t.Run("3-G", func(t *testing.T) { return })
if true {
t.Fail()
}
})
}
上面的日志没有准确地显示我的过程使用的内存(6 GB的30 MB)。我想知道,如果我的过程超过了一定的阈值,是否有可能触发以下一个或两个,但是由于我似乎无法对我的过程使用了多少内存(至少使用GO的内部memstats) - 不确定这对任何人都有用:
--- FAIL: TestVariousQueries (0.00s)
--- FAIL: TestVariousQueries/7-node (0.00s)
--- PASS: TestVariousQueries/7-node/0-G (0.00s)
--- PASS: TestVariousQueries/7-node/1-G (0.00s)
--- PASS: TestVariousQueries/7-node/2-G (0.00s)
--- PASS: TestVariousQueries/7-node/3-G (0.00s)
FAIL
我知道以下页面:
https://golang.org/pkg/runtime/#memstats但是,30 MB至6 GB的差异似乎很奇怪。 经过一番调试后,事实证明,我正在使用的GO软件包正在执行C/C ++不安全的Alloc/Free-不确定是否有使用GO MEM统计数据跟踪这些分配的方法? 此时 - 我可能不得不调用OS命令以获取操作系统告诉我我的过程要进行多少内存。
这个帖子似乎有一些很好的信息/答案:如何分析golang记忆?
https://github.com/pbnjay/memory
如果在我们的代码中找到问题,请参见测试输出失败。您可以与
func bToMb(b uint64) uint64 {
return b / 1024 / 1024
}
func PrintMemUsage(text string) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("%v: ", text)
fmt.Printf("HeapAlloc = %v MB", bToMb(m.HeapAlloc))
fmt.Printf(" HeapInuse = %v MB", bToMb(m.HeapInuse))
fmt.Printf(" HeapIdle = %v MB", bToMb(m.HeapIdle))
fmt.Printf(" HeapReleased = %v MB", bToMb(m.HeapReleased))
fmt.Printf(" HeapSys = %v MB", bToMb(m.HeapSys))
fmt.Printf(" Alloc = %v MB", bToMb(m.Alloc))
fmt.Printf(" TotalAlloc = %v MB", bToMb(m.TotalAlloc))
fmt.Printf(" Sys = %v MB", bToMb(m.Sys))
fmt.Printf(" NumGC = %v\n", m.NumGC)
}
从https://pkg.go.dev/cmd/go/internal/test在构建测试二进制的一部分,GO测试运行次兽医 及其测试源文件以识别重大问题。如果去兽医 发现任何问题,去测试报告,并且不运行测试 二进制。默认GO VET检查仅一个高信心子集 用过的。该子集是:“原子”,“布尔”,“ buildtags”,“ errorsas', “ Ifaceaserser”,“ nilfunc”,“ printf”和“ StringIntConv”。你可以看到 这些文档和其他兽医测试通过“ Go Doc CMD/VET”进行。 要禁用GO VET的运行,请使用-Vet = OFF标志。全部运行 检查,使用-VET =所有标志。
我在测试方面也有类似的经验,通过调试,我设法发现通过runtime.GC()
debug.FreeOSMemory()
的辅助功能有一个错误。