call to (*testing.T).FailNow from a non-test goroutine 是什么意思?
go vet
1 | [github.com/samber/lo] |
这个错误消息 “call to (*testing.T).FailNow from a non-test goroutine” 是在 Go 语言的测试框架中出现的,它表明在测试过程中出现了一个特定的问题。让我来解释一下这个错误的含义和可能的原因:
- 错误的含义:
这个错误意味着 testing.T 的 FailNow() 方法被从非测试 goroutine 中调用了。在 Go 的测试框架中,FailNow() 方法应该只在主测试 goroutine 中调用。
- 为什么会出现这个错误:
通常,这个错误发生在以下情况:
a. 在测试函数中创建了新的 goroutine。
b. 在这个新的 goroutine 中调用了 t.FailNow() 或其他会导致 FailNow() 被调用的方法(如 t.Fatal())。
- 为什么这是一个问题:
FailNow() 方法设计用来立即停止当前测试。但是,如果它在非主测试 goroutine 中被调用,它无法正确地停止整个测试,这可能导致不可预知的行为。
- 如何修复:
要解决这个问题,你可以:
a. 避免在新的 goroutine 中直接调用 FailNow() 或 Fatal()。
b. 使用 channel 来通知主测试 goroutine 发生了失败,然后在主 goroutine 中调用 FailNow()。
c. 使用 testing.T.Run() 来运行可能需要在单独 goroutine 中执行的子测试。
- 示例修复:
这里有一个简单的例子来说明如何修复这个问题:
1 | package main |
在这个例子中:
TestProblemExample演示了会导致错误的情况。TestFixedExample展示了如何正确地在 goroutine 中处理错误,并在主测试 goroutine 中报告失败。
通过使用 channel 来同步 goroutine 并在主测试函数中检查错误,我们避免了直接在 goroutine 中调用 t.Fatal(),从而解决了这个问题。
记住,在编写并发测试时,始终要确保错误报告和测试控制流保持在主测试 goroutine 中。这样可以确保测试框架能够正确地管理测试的执行和报告。
执行 gofmt会增加一行,在原来// +build profile基础上新增//go:build profile
//go:build profile 和 // +build profile 是 Go 语言中用于构建约束的两种语法,它们在语法和使用上有一些区别。
主要区别
语法:
//go:build profile是一种新的语法,从 Go 1.17 开始引入,旨在统一和简化构建约束的表示。// +build profile是旧的语法,直到 Go 1.16 都在使用。
可读性:
- 新的
//go:build语法更加直观,能够更清晰地表达条件,例如可以通过逻辑运算符(如&&和||)组合多个条件。 - 旧语法的可读性相对较低,特别是在处理复杂条件时。
- 新的
兼容性:
- 从 Go 1.17 开始,推荐使用
//go:build语法,未来的版本可能会逐步弃用旧语法。
- 从 Go 1.17 开始,推荐使用
为什么 gofmt 会增加一行
当你使用 gofmt 格式化代码时,它会自动将旧的构建约束(// +build ...)转换为新的语法(//go:build ...)。这可能会导致在文件中看到多余的空行,因为 gofmt 在转换时会在新语法前添加一行空行,以分隔构建约束和代码。这样做可以增强代码的可读性。
示例
1 | // Old syntax |
总结
- 使用
//go:build是推荐的做法。 gofmt会自动转换旧语法,并可能在转换过程中添加空行以提高可读性。
我给这个项目gofmt时对方提到了这个问题
https://github.com/googleforgames/agones/pull/4000/files
https://github.com/golang/go/issues/41184
https://github.com/golang/go/issues/48383
https://stackoverflow.com/questions/69180548/how-do-i-prevent-gofmt-adding-gobuild-test
原文链接: https://dashen.tech/2018/08/27/Go静态分析工具报告的问题/
版权声明: 转载请注明出处.