Goでランダム関数を使う時にグローバル変数に入れる事でスタブテストがしやすくなる
以下の事に困ってる人に役に立つ内容になっている
・ランダムな値のスタブのテストが出来ない。
・日付を扱ったスタブのテストが出来ない
・引数に上記のような値を入れて解決してるが微妙だと思ってる人
結論
※結論から先に記載しておく。そこに行きついた背景などは下に書いておく。
ランダム関数をグローバル変数に入れて、使用する箇所で呼び出せばよい。
こんな感じ↓
// hoge.go
// グローバル変数に関数をぶち込む
var getRandNum = func(num uint) uint {
rand.Seed(time.Now().UnixNano())
return uint(rand.Intn(int(num)) + 1)
}
func hoge() string {
var num uint = 7
randNum := getRandNum(num)
if randNum%2 == 0 {
return "偶数"
}
if randNum%2 == 1 {
return "奇数"
}
return "異常"
}
//hoge_test.go
func TestName(t *testing.T) {
type testSet struct {
num uint
expected string
}
testCase := []testSet{
{13, "奇数"},
{20, "偶数"},
{15, "奇数"},
}
for _, test := range testCase {
// グローバル変数に定数値を挿入
getRandNum = func(num uint) uint { return test.num }
actual := hoge()
if actual != test.expected {
t.Errorf("got %v\nwant %v", actual, test.expected)
}
}
}
困ったこと
こんな感じのソースコードを書いていて、いざテストを書こうとしたときに書けなかった。
func hoge() string {
var num uint = 7
rand.Seed(time.Now().UnixNano())
randNum := uint(rand.Intn(int(num)) + 1)
if randNum%2 == 0 {
return "偶数"
}
if randNum%2 == 1 {
return "奇数"
}
return "異常"
}
理由は、ランダムな値をスタブすることが出来なかった。
解決策は他にもあった。
例えばこんな感じに引数にランダム値を取らせル方法
func hoge() string {
var num uint = 7
rand.Seed(time.Now().UnixNano())
randNum := uint(rand.Intn(int(num)) + 1)
return huga(randNum)
}
func huga(num uint) string {
if num%2 == 0 {
return "偶数"
}
if num%2 == 1 {
return "奇数"
}
return "異常"
}
これが一般的な解決策にも思えるが、これだと呼び出し側がランダムな値を渡すことを知ってしまうし、
他のケースだと引数が多い場合もあると思う。
なのでスマートじゃない。ってことでグローバル変数を使って処理を書いた。
※ グローバル変数を小文字スタートで定義したらパッケージ内からしかさせないので、外にそんなに影響がないと思ってる。