Test_xxx功能是否安全,无法访问 golang 中的共享数据?

我对戈朗单元测试感到困惑。

我有 2 个 funcs ,喜欢 和 。
在,i将更改一个全局变量,可以看到更改吗?Test_xxxTest_1Test_2Test_1Test_2

此外,如果我使用而不是更改全局 var,其他功能是否会感知到修补?
即,我是否有必要在返回时使用延迟来取消功能替换?monkey patchTest_xxxTest_xxx


当年话下
浏览 80回答 5
5回答

慕的地10843

func 在 golang 中访问共享数据是否安全?Test_xxx答案完全取决于是否允许这些测试函数并行运行。默认情况下,按顺序调用给定包的测试函数。但是,如果go test在两个测试函数中调用 t.Parallel(),并且两个函数访问(写/写或写/读)相同的全局变量,它们之间没有任何同步,你可能会得到一场数据竞赛。要修复想法,请考虑以下简单测试文件:package mainimport (    "fmt"    "testing")var count = 0func 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--FAILexit status 1FAIL    whatever    0.730s这应该使您确信在测试中处理全局状态时应该小心。如果可以的话,最好的办法是完全避免全局状态。或者,请记住,在激活并行测试执行后立即,必须注意同步对全局状态的访问。

饮歌长啸

Test_1,我将更改一个全局变量,Test_2可以看到更改吗?是的。var global = 0func Test_1(t *testing.T) {&nbsp; &nbsp; for i := 0; i < 1000; i++ {&nbsp; &nbsp; &nbsp; &nbsp; global++&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println(global)}func Test_2(t *testing.T) {&nbsp; &nbsp; for i := 0; i < 1000; i++ {&nbsp; &nbsp; &nbsp; &nbsp; global++&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println(global)}外=== RUN&nbsp; &nbsp;Test_11000--- PASS: Test_1 (0.00s)=== RUN&nbsp; &nbsp;Test_222000--- PASS: Test_22 (0.00s)PASS我有必要在Test_xxx返回时使用延迟来获取功能子结构吗?您可以使用清理功能删除全局变量的更改func Test_1(t *testing.T) {&nbsp; &nbsp; t.Cleanup(func() {&nbsp; &nbsp; &nbsp; &nbsp; global = 0&nbsp; &nbsp; })&nbsp; &nbsp; for i := 0; i < 1000; i++ {&nbsp; &nbsp; &nbsp; &nbsp; global++&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println(global)}PLAYGROUND

千巷猫影

虽然这是可能的,但您可能需要考虑从两个测试初始化全局变量,以生成一致的行为。从命令行运行测试时,可以选择仅运行一个测试函数 (),否则将生成不一致的结果。gogo test foo -test.run Test_1访问全局变量受各种竞赛的影响(在某些情况下涉及部分读取数据,因为它在其他地方被覆盖)返回无意义/不可能的值!使用某种方式来防止这些种族:sync.Muteximport (&nbsp; &nbsp; "sync")var mu sync.Mutexvar global intfunc readGlobal() int {&nbsp; &nbsp; mu.Lock()&nbsp; &nbsp; defer mu.Unock()&nbsp; &nbsp; return global}func writeGlobal(val int) {&nbsp; &nbsp; mu.Lock()&nbsp; &nbsp; defer mu.Unock()&nbsp; &nbsp; global = val}// your test functions

胡说叔叔

Test_1,我将更改一个全局变量,Test_2可以看到更改吗?它仅在某些特定条件下才是安全的:您在单个戈鲁廷中运行测试。不能在测试中使用。t.Parallel()您只能运行一次测试。否则,您必须实现额外的拆卸例程,以便在每次测试运行后将数据重置为其原始状态。您无法更改文件中的测试顺序。开发人员过去依赖函数顺序并不重要。对于在不更改其代码的情况下移动测试的人来说,对顺序的依赖可能会非常混乱。这些只是我脑海中的几个例子。打破这些条件中的任何一个都会破坏测试。这就是为什么这种测试被称为脆弱。检查是否可以避免这种情况。这通常需要更改代码并引入新的模式,如依赖注入。编写代码是一件好事。您使它更加模块化,更易于维护。testable

紫衣仙女

请注意,未来的 Go 版本可能会更改测试的运行顺序,例如,通过随机化顺序。如果您的测试依赖于之前运行的事实并更改了全局变量,则它将中断。Test_1Test_2更改全局变量的一个好习语是这样的:func Test_1(t *testing.T) {&nbsp; oldVal := myGlobalVariable&nbsp; defer func() { myGlobalVariable = oldVal }&nbsp; // rest of the test}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go