gpt4 book ai didi

unit-testing - Go 中的模拟随机生成器

转载 作者:IT王子 更新时间:2023-10-29 01:47:09 25 4
gpt4 key购买 nike

出于测试目的,我想在 Go 中模拟随机数。所以我创建了随机界面。在单元测试期间,我返回标识函数,而为了实现,我使用 rand 包生成一个随机数。

这是在 Go 中模拟随机数的正确方法吗?任何帮助表示赞赏。

去 Playground :https://play.golang.org/p/bibNnmY2t1g

主要内容:

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))
}

测试:

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)
}
})
}
}

最佳答案

您的示例没有真正使用 Random 接口(interface),因为模拟是在 Randomizer 类型的函数字段级别完成的。

如果可能的话,我建议放弃函数字段和函数,而是定义 Random 接口(interface)的两个单独实现。您可以为此使用空结构,它们起初可能看起来很奇怪,但它们具有占用 0 字节内存的良好特性。

推荐的主要原因是,当您使用函数字段时,您将失去将结构类型值与 reflect.DeepEqual 进行比较的能力。这是因为只有当它们具有相同的类型并且都是 nil 时,两个函数值才相等。

作为示例,让我们首先查看您的 TestNewRandomizer,它是上述问题的一个症状。在测试中你只是比较返回值的类型,这是编译器已经确保的,所以测试是毫无意义的。

现在,假设您放弃了测试,因为它没有用,但出于某种原因您保留了函数字段。因此,任何依赖于 *Randomizer 的结构类型也将无法使用 DeepEqual 进行测试,并且在尝试对该类型进行测试时您将遇到同样的困难.

package main

import (
"time"
"math/rand"
"fmt"
)

func init() {
rand.Seed(time.Now().UnixNano())
}

type Random interface {
Uint(_ uint) uint
}

type Randomizer struct {}

func NewRandomizer() Randomizer {
return Randomizer{}
}

func (r Randomizer) Uint(n uint) uint {
return uint(rand.Uint64())
}

type FakeRandomizer struct {}

func NewFakeRandomizer() FakeRandomizer {
return FakeRandomizer{}
}

func (r FakeRandomizer) Uint(n uint) uint {
return n
}

func main() {
fakeRnd := NewFakeRandomizer().Uint
fmt.Println(fakeRnd(1))
fmt.Println(fakeRnd(2))

realRnd := NewRandomizer().Uint
fmt.Println(realRnd(0))
fmt.Println(realRnd(0))
}

请注意,我有意返回值而不是指针,因为空结构比指针小。

关于unit-testing - Go 中的模拟随机生成器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48360260/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com