For my tests purpose, I would like to mock random numbers in Go. So I created the Random interface. During unit testing I return the identity function, while for implementation I generate a random number with rand package.
It is the right way for mocking random numbers in Go? Any help appreciated.
Go Playground: https://play.golang.org/p/bibNnmY2t1g
main:
package main import ( "time" "math/rand" "fmt" ) func init() { rand.Seed(time.Now().UnixNano()) } type Random interface { Uint(_ uint) uint } type rndGenerator func(n uint) uint type Randomizer struct { fn rndGenerator } func NewRandomizer(fn rndGenerator) *Randomizer { return &Randomizer{fn: fn} } func (r *Randomizer) Uint(n uint) uint { return r.fn(n) } func fakeRand(n uint) uint { return n } func realRand(_ uint) uint { return uint(rand.Uint64()) } func main() { fakeRnd := NewRandomizer(fakeRand).Uint fmt.Println(fakeRnd(1)) fmt.Println(fakeRnd(2)) realRnd := NewRandomizer(realRand).Uint fmt.Println(realRnd(0)) fmt.Println(realRnd(0)) } test:
package main import ( "testing" "math/rand" "reflect" ) func TestNewRandomizer(t *testing.T) { fn := func(n uint) uint { return n } type args struct { fn rndGenerator } tests := []struct { name string args args want *Randomizer }{ { "test", args{fn}, &Randomizer{fn}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := NewRandomizer(tt.args.fn); reflect.TypeOf(got) != reflect.TypeOf(tt.want) { t.Errorf("NewRandomizer() = %v, want %v", got, tt.want) } }) } } func TestRandomer_Uint(t *testing.T) { rnd := uint(rand.Uint64()) type fields struct { fn rndGenerator } type args struct { n uint } tests := []struct { name string fields fields args args want uint }{ { "test", fields{func(n uint) uint { return n }}, args{rnd}, rnd, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Randomizer{ fn: tt.fields.fn, } if got := r.Uint(tt.args.n); got != tt.want { t.Errorf("Randomizer.Uint() = %v, want %v", got, tt.want) } }) } } func Test_fakeRand(t *testing.T) { rnd := uint(rand.Uint64()) type args struct { n uint } tests := []struct { name string args args want uint }{ { "test", args{rnd}, rnd, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := fakeRand(tt.args.n); got != tt.want { t.Errorf("fakeRand() = %v, want %v", got, tt.want) } }) } } func Test_realRand(t *testing.T) { type args struct { in0 uint } tests := []struct { name string args args want bool }{ { "test", args{0}, true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := realRand(tt.args.in0); got < 1 { t.Errorf("realRand() = %v, want %v", got, tt.want) } }) } }