亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Test_xxx功能是否安全,無法訪問 golang 中的共享數據?

Test_xxx功能是否安全,無法訪問 golang 中的共享數據?

Go
當年話下 2022-09-12 15:44:23
我對戈朗單元測試感到困惑。我有 2 個 funcs ,喜歡 和 。在,i將更改一個全局變量,可以看到更改嗎?Test_xxxTest_1Test_2Test_1Test_2此外,如果我使用而不是更改全局 var,其他功能是否會感知到修補?即,我是否有必要在返回時使用延遲來取消功能替換?monkey patchTest_xxxTest_xxx
查看完整描述

5 回答

?
慕的地10843

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

這應該使您確信在測試中處理全局狀態時應該小心。如果可以的話,最好的辦法是完全避免全局狀態。或者,請記住,在激活并行測試執行后立即,必須注意同步對全局狀態的訪問。


查看完整回答
反對 回復 2022-09-12
?
飲歌長嘯

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)

}

PLAYGROUND


查看完整回答
反對 回復 2022-09-12
?
千巷貓影

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


查看完整回答
反對 回復 2022-09-12
?
胡說叔叔

TA貢獻1804條經驗 獲得超8個贊

Test_1,我將更改一個全局變量,Test_2可以看到更改嗎?

它僅在某些特定條件下才是安全的:

  1. 您在單個戈魯廷中運行測試。不能在測試中使用。t.Parallel()

  2. 您只能運行一次測試。否則,您必須實現額外的拆卸例程,以便在每次測試運行后將數據重置為其原始狀態。

  3. 您無法更改文件中的測試順序。開發人員過去依賴函數順序并不重要。對于在不更改其代碼的情況下移動測試的人來說,對順序的依賴可能會非?;靵y。

這些只是我腦海中的幾個例子。打破這些條件中的任何一個都會破壞測試。這就是為什么這種測試被稱為脆弱。

檢查是否可以避免這種情況。

這通常需要更改代碼并引入新的模式,如依賴注入。編寫代碼是一件好事。您使它更加模塊化,更易于維護。testable


查看完整回答
反對 回復 2022-09-12
?
紫衣仙女

TA貢獻1839條經驗 獲得超15個贊

請注意,未來的 Go 版本可能會更改測試的運行順序,例如,通過隨機化順序。如果您的測試依賴于之前運行的事實并更改了全局變量,則它將中斷。Test_1Test_2


更改全局變量的一個好習語是這樣的:


func Test_1(t *testing.T) {

  oldVal := myGlobalVariable

  defer func() { myGlobalVariable = oldVal }

  // rest of the test

}


查看完整回答
反對 回復 2022-09-12
  • 5 回答
  • 0 關注
  • 103 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號