在go中测试非返回方法

时间:2015-06-05 00:41:02

标签: testing go

我有一个简单的方法,只检查参数是否为空,然后根据结构字段调用2个方法之一。
我该如何测试?

func (cT *customType) someMethod(message string) {
    if message == ""{
        return
    }

    if cT.value == nil {
        cT.doFunctionOne()
    } else {
        cT.doFunctionTwo()
    }
}

在Javascript中,我会在doFunctionOne()上创建一个间谍并模拟该对象 模拟在Go也很有效,但我怎么做'间谍'部分呢? 还是有另一种惯用的方法来测试这种方法吗?

3 个答案:

答案 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()
    }
}

我们必须提供一种明确更改doFunctionOnedoFunctionTwo实施的方法。我们可以使用接口概括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)

  1. 您可以在每次函数调用之前添加日志。
  2. 注入您自己的记录器实现,例如[]字符串。
  3. 检查字符串切片是否有匹配的字符串。
  4. 但是,如果您正在创建一个函数工厂,那么将函数返回给调用者并且调用者将运行该函数会更好。
    然后测试很简单。

    其次,只有两种功能,流功能和逻辑功能。 您在同一个函数中混合了流和逻辑。 测试难度只是这种不良做法的一个症状。