gpt4 book ai didi

在 go 中使用 channel 返回值测试发射器函数

转载 作者:数据小太阳 更新时间:2023-10-29 03:23:13 27 4
gpt4 key购买 nike

我很难对我的发射器函数进行测试,该函数通过数据管道的 channel 传递结果。此功能将定期触发并从数据库中提取记录。我为这个问题编译了一个精简的完成版本,真正的代码会更复杂,但会遵循相同的模式。为了进行测试,我模拟了对数据库的访问,因为我想测试 Emitter 函数的行为。

我想代码不仅仅是文字:

这是我要测试的方法:

//EmittRecord pull record from database
func EmittRecord(svc Service, count int) <-chan *Result {
out := make(chan *Result)

go func() {
defer close(out)
for i := 0; i < count; i++ {
r, err := svc.Next()
if err != nil {
out <- &Result{Error: err}
continue
}
out <- &Result{Payload: &Payload{
Field1: r.Field1,
Field2: r.Field2,
}, Error: nil}
}

}()

return out
}

我有几个带有接口(interface)的类型:

//Record is a Record from db
type Record struct {
Field1 string
Field2 string
}

//Payload is a record for the data pipeline
type Payload struct {
Field1 string
Field2 string
}

//Result is a type for the data pipeline
type Result struct {
Payload *Payload
Error error
}

//Service is an abstraction to access the database
type Service interface {
Next() (*Record, error)
}

这是我用于测试的服务模拟:

//MockService is a struct to support testing for mocking the database
type MockService struct {
NextMock func() (*Record, error)
}

//Next is an Implementation of the Service interface for the mock
func (m *MockService) Next() (*Record, error) {
if m.NextMock != nil {
return m.NextMock()
}
panic("Please set NextMock!")
}

最后,这是我的测试方法,但它不起作用。它没有达到完成的情况,也没有达到 1*time.Second 超时情况……测试只是超时。我想我在这里遗漏了一些东西。

 func TestEmitter(t *testing.T) {

tt := []struct {
name string
svc runner.Service
expectedResult runner.Result
}{

{name: "Database returns error",
svc: &runner.MockService{
NextMock: func() (*runner.Record, error) {
return nil, fmt.Errorf("YIKES")
},
},
expectedResult: runner.Result{Payload: nil, Error: fmt.Errorf("RRRR")},
},
{name: "Database returns record",
svc: &runner.MockService{
NextMock: func() (*runner.Record, error) {
return &runner.Record{
Field1: "hello",
Field2: "world",
}, nil
},
},
},
}

for _, tc := range tt {

t.Run(tc.name, func(t *testing.T) {
done := make(chan bool)
defer close(done)

var output <-chan *runner.Result
go func() {
output = runner.EmittRecord(tc.svc, 1)
done <- true
}()
found := <-output
<-done
select {
case <-done:
case <-time.After(1 * time.Second):
panic("timeout")
}

if found.Error.Error() != tc.expectedResult.Error.Error() {
t.Errorf("FAIL: %s, expected: %s; but got %s", tc.name, tc.expectedResult.Error.Error(), found.Error.Error())

} else if reflect.DeepEqual(found.Payload, tc.expectedResult.Payload) {
t.Errorf("FAIL: %s, expected: %+v; got %+v", tc.name, tc.expectedResult.Payload, found.Payload)
}

})
}

}

如果有人能给我一些我在这里遗漏的建议,也许还有一些输入如何验证 EmittRecord 函数的计数,那就太好了,它现在只设置为 1 提前致谢

//已编辑:@Lansana 评论的预期结果

最佳答案

您确定将测试中的预期结果设置为正确的值吗?

在测试的第一个 slice 中,您期望一个 fmt.Errorf("RRRR"),但模拟返回一个 fmt.Errorf("YIKES") .

然后在实际的测试条件中,你这样做:

if found.Error.Error() != "Hello" {
t.Errorf("FAIL: %s, expected: %s; but got %s", tc.name, tc.expectedResult.Error.Error(), found.Error.Error())
}

您正在检查 “Hello”。您不应该检查消息 "YIKES" 是否有错误吗?

我认为你的逻辑很好,但你的测试写得不正确。查看我的Go Playground example在这里并运行代码。当你运行它时,你会看到没有输出或出现 panic 。这是因为代码在 main 中通过了我的测试条件。

您正在通过更多 channel 为您的测试增加更多的复杂性,如果这些额外的 channel 无效,那么您可能会有一些误报,让您认为您的业务逻辑是错误的。在这种情况下,它实际上似乎在正常工作。

这是我的 Playground 示例中代码的亮点。 (测试你逻辑的部分):

func main() {
svc1 := &MockService{
NextMock: func() (*Record, error) {
return nil, errors.New("foo")
},
}
for item := range EmittRecord(svc1, 5) {
if item.Payload != nil {
panic("item.Payload should be nil")
}
if item.Error == nil {
panic("item.Error should be an error")
}
}

svc2 := &MockService{
NextMock: func() (*Record, error) {
return &Record{Field1: "Hello ", Field2: "World"}, nil
},
}
for item := range EmittRecord(svc2, 5) {
if item.Payload == nil {
panic("item.Payload should have a value")
}
if item.Payload.Field1 + item.Payload.Field2 != "Hello World" {
panic("item.Payload.Field1 and item.Payload.Field2 are invalid!")
}
if item.Error != nil {
panic("item.Error should be nil")
}
}
}

以上代码的输出是空的。没有 panic 。因此,它成功了。

尝试将您的测试简化为工作状态,然后从那里增加更多的复杂性。 :)

关于在 go 中使用 channel 返回值测试发射器函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49456417/

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