5 回答
TA贡献1785条经验 获得超8个赞
func 在 golang 中访问共享数据是否安全?
Test_xxx
答案完全取决于是否允许这些测试函数并行运行。
默认情况下,按顺序调用给定包的测试函数。但是,如果go test
在两个测试函数中调用
t.Parallel(),
并且两个函数访问(写/写或写/读)相同的全局变量,它们之间没有任何同步,
你可能会得到一场数据竞赛。
要修复想法,请考虑以下简单测试文件:
package main
import (
"fmt"
"testing"
)
var count = 0
func Test_1(t *testing.T) {
t.Parallel()
count++
fmt.Println(count)
}
func Test_2(t *testing.T) {
t.Parallel()
count++
fmt.Println(count)
}
如果你跑步,比赛探测器会拍打你的手腕:go test -race
==================
WARNING: DATA RACE
--snip--
FAIL
exit status 1
FAIL whatever 0.730s
这应该使您确信在测试中处理全局状态时应该小心。如果可以的话,最好的办法是完全避免全局状态。或者,请记住,在激活并行测试执行后立即,必须注意同步对全局状态的访问。
TA贡献1951条经验 获得超3个赞
Test_1,我将更改一个全局变量,Test_2可以看到更改吗?
是的。
var global = 0
func Test_1(t *testing.T) {
for i := 0; i < 1000; i++ {
global++
}
fmt.Println(global)
}
func Test_2(t *testing.T) {
for i := 0; i < 1000; i++ {
global++
}
fmt.Println(global)
}
外
=== RUN Test_1
1000
--- PASS: Test_1 (0.00s)
=== RUN Test_22
2000
--- PASS: Test_22 (0.00s)
PASS
我有必要在Test_xxx返回时使用延迟来获取功能子结构吗?
您可以使用清理功能删除全局变量的更改
func Test_1(t *testing.T) {
t.Cleanup(func() {
global = 0
})
for i := 0; i < 1000; i++ {
global++
}
fmt.Println(global)
}
TA贡献1829条经验 获得超7个赞
虽然这是可能的,但您可能需要考虑从两个测试初始化全局变量,以生成一致的行为。从命令行运行测试时,可以选择仅运行一个测试函数 (),否则将生成不一致的结果。gogo test foo -test.run Test_1
访问全局变量受各种竞赛的影响(在某些情况下涉及部分读取数据,因为它在其他地方被覆盖)返回无意义/不可能的值!使用某种方式来防止这些种族:sync.Mutex
import (
"sync"
)
var mu sync.Mutex
var global int
func readGlobal() int {
mu.Lock()
defer mu.Unock()
return global
}
func writeGlobal(val int) {
mu.Lock()
defer mu.Unock()
global = val
}
// your test functions
TA贡献1804条经验 获得超8个赞
Test_1,我将更改一个全局变量,Test_2可以看到更改吗?
它仅在某些特定条件下才是安全的:
您在单个戈鲁廷中运行测试。不能在测试中使用。
t.Parallel()
您只能运行一次测试。否则,您必须实现额外的拆卸例程,以便在每次测试运行后将数据重置为其原始状态。
您无法更改文件中的测试顺序。开发人员过去依赖函数顺序并不重要。对于在不更改其代码的情况下移动测试的人来说,对顺序的依赖可能会非常混乱。
这些只是我脑海中的几个例子。打破这些条件中的任何一个都会破坏测试。这就是为什么这种测试被称为脆弱。
检查是否可以避免这种情况。
这通常需要更改代码并引入新的模式,如依赖注入。编写代码是一件好事。您使它更加模块化,更易于维护。testable
TA贡献1839条经验 获得超15个赞
请注意,未来的 Go 版本可能会更改测试的运行顺序,例如,通过随机化顺序。如果您的测试依赖于之前运行的事实并更改了全局变量,则它将中断。Test_1Test_2
更改全局变量的一个好习语是这样的:
func Test_1(t *testing.T) {
oldVal := myGlobalVariable
defer func() { myGlobalVariable = oldVal }
// rest of the test
}
- 5 回答
- 0 关注
- 79 浏览
添加回答
举报