- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我很难对我的发射器函数进行测试,该函数通过数据管道的 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/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!