我有一个简单的方法,只检查参数是否为空,然后根据结构字段调用2个方法之一。
我该如何测试?
func (cT *customType) someMethod(message string) {
if message == ""{
return
}
if cT.value == nil {
cT.doFunctionOne()
} else {
cT.doFunctionTwo()
}
}
在Javascript中,我会在doFunctionOne()
上创建一个间谍并模拟该对象
模拟在Go
也很有效,但我怎么做'间谍'部分呢?
还是有另一种惯用的方法来测试这种方法吗?
答案 0 :(得分:3)
首先:您不会将方法命名为“doFunctionOne”,而是命名为“methodOne”: - )
如果doFunctionOne和doFunctionTwo都没有任何可观察的效果,那么测试它绝对没有意义。因此,我们可以假设它们确实具有可观察的副作用,无论是在环境上还是在调用它们的customType上。
现在只测试这些副作用。如果两种方法都返回,这是微不足道的。如果他们旋转无限循环,它会变得更难,但仍然可行。
恕我直言,没有必要“测试”这种方法的意思是“测试是否根据价值调用一个或两个”:对我而言,这是低级别,过多增加覆盖计数。如果你调用某种方法它必须做某事(可观察到的效果),你应该检查这种效果,而不是内部工作。
答案 1 :(得分:1)
在Go中模拟对象的惯用方法是使其显式化。健康的界面本身应该是可测试的。所以,如果我们有这样的事情:
type customType struct {
value int
}
func (c customType) doFunctionOne() {
fmt.Println("Method #1")
}
func (c customType) doFunctionTwo() {
fmt.Println("Method #2")
}
func (c customType) someMethod() {
if c.value <= 0 {
c.doFunctionOne()
} else {
c.doFunctionTwo()
}
}
我们必须提供一种明确更改doFunctionOne
和doFunctionTwo
实施的方法。我们可以使用接口概括someMethod
行为:
type customType struct {
myValue int
}
func (c customType) doFunctionOne() {
fmt.Println("Method #1")
}
func (c customType) doFunctionTwo() {
fmt.Println("Method #2")
}
func (c customType) value() int {
return c.myValue
}
type Interface interface {
value() int
doFunctionOne()
doFunctionTwo()
}
func someMethod(i Interface) {
if i.value() <= 0 {
i.doFunctionOne()
} else {
i.doFunctionTwo()
}
}
type customTestingType struct {
t *testing.T
}
func (c customTestingType) doFunctionOne() {
c.t.Log("Working")
}
func (c customTestingType) doFunctionTwo() {
c.t.Error("Not working")
}
func (c customTestingType) value() int {
return 0
}
func TestInterface(t *testing.T) {
someMethod(customTestingType{t})
}
肯定会有更多方法来提供此行为,但这取决于您的类型的特定声明。例如,您可以查看httptest
包。也就是说,如果你真的想以这种方式嘲笑你的类型(非语言),你可以unsafe monkey patching:
package main
import (
"fmt"
"reflect"
"github.com/bouk/monkey"
)
type customType struct {
myValue int
}
func (c customType) doFunctionOne() {
fmt.Println("Method #1")
}
func (c customType) doFunctionTwo() {
fmt.Println("Method #2")
}
func (c customType) someMethod() {
if c.myValue <= 0 {
c.doFunctionOne()
} else {
c.doFunctionTwo()
}
}
func main() {
c := customType{0}
monkey.PatchInstanceMethod(reflect.TypeOf(c), "doFunctionOne",
func(c customType) {
fmt.Println("Method #1, but patched")
})
monkey.PatchInstanceMethod(reflect.TypeOf(c), "doFunctionTwo",
func(c customType) {
fmt.Println("Method #2, but patched")
})
c.someMethod()
}
答案 2 :(得分:0)
但是,如果您正在创建一个函数工厂,那么将函数返回给调用者并且调用者将运行该函数会更好。
然后测试很简单。
其次,只有两种功能,流功能和逻辑功能。 您在同一个函数中混合了流和逻辑。 测试难度只是这种不良做法的一个症状。