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()
您只能運行一次測試。否則,您必須實現額外的拆卸例程,以便在每次測試運行后將數據重置為其原始狀態。
您無法更改文件中的測試順序。開發人員過去依賴函數順序并不重要。對于在不更改其代碼的情況下移動測試的人來說,對順序的依賴可能會非?;靵y。
這些只是我腦海中的幾個例子。打破這些條件中的任何一個都會破壞測試。這就是為什么這種測試被稱為脆弱。
檢查是否可以避免這種情況。
這通常需要更改代碼并引入新的模式,如依賴注入。編寫代碼是一件好事。您使它更加模塊化,更易于維護。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 關注
- 103 瀏覽
添加回答
舉報