单元测试不同的标志值

时间:2016-08-02 04:14:06

标签: unit-testing go

我有以下Golang代码:

func getConfigFile() string {
    var configFile string
    flag.StringVar(&configFile, "config", "", "File containing configuration")
    flag.Parse()
    return configFile
}

这个函数在我的代码的其他地方使用,我想在用户为config参数提供不同的值时对这里发生的事情进行单元测试(配置文件名在其他地方使用)。
有没有办法告诉标志包在测试时为config参数返回不同的值?

2 个答案:

答案 0 :(得分:1)

我发现,为了测试自定义标志最好创建一个自定义标志集,这样我就可以完全测试标志,包括-h选项而不退出测试。希望附加的代码可以为您提供有关如何在代码上实现测试的想法:

package main

import (
    "flag"
    "fmt"
    "os"
    "reflect"
    "testing"
)

// Test Helper
func expect(t *testing.T, a interface{}, b interface{}) {
    if a != b {
        t.Errorf("Expected: %v (type %v)  Got: %v (type %v)", a, reflect.TypeOf(a), b, reflect.TypeOf(b))
    }
}

type Flags struct {
    ConfigFile string
}

func (self *Flags) Parse(fs *flag.FlagSet) (*Flags, error) {
    fs.StringVar(&self.ConfigFile, "config", "", "File containing configuration")

    err := fs.Parse(os.Args[1:])
    if err != nil {
        return nil, err
    }

    return self, nil
}

func main() {

    fs := flag.NewFlagSet("test", flag.ContinueOnError)

    parser := Flags{}
    flags, err := parser.Parse(fs)
    if err != nil {
        panic(err)
    }
    fmt.Println(flags)

}

func TestFlags(t *testing.T) {
    oldArgs := os.Args
    defer func() { os.Args = oldArgs }()
    var flagTest = []struct {
        flag     []string
        name     string
        expected interface{}
    }{
        {[]string{"cmd", "-config", "config.yaml"}, "ConfigFile", "config.yaml"},
        {[]string{"cmd", "-config", "config.json"}, "ConfigFile", "config.json"},
        {[]string{"cmd", "-v"}, "Version", true},
    }

    for _, f := range flagTest {
        os.Args = f.flag
        p := &Flags{}
        fs := flag.NewFlagSet("test", flag.ContinueOnError)

        flags, err := p.Parse(fs)
        if err != nil {
            t.Error(err)
        }

        refValue := reflect.ValueOf(flags).Elem().FieldByName(f.name)
        switch refValue.Kind() {
        case reflect.Bool:
            expect(t, f.expected, refValue.Bool())
        case reflect.String:
            expect(t, f.expected, refValue.String())
        }
    }

}

我也把它放在这里:https://play.golang.org/p/h1nok1UMLA希望它可以给你一个想法。

答案 1 :(得分:0)

如果您按照以下代码进行更改,则go test将失败,但go test -config testconfig将通过。并非我们不需要在flag.Parse()中调用init(),因为测试包会调用它(正如Rob Pike在https://groups.google.com/d/msg/golang-nuts/uSFM8jG7yn4/PIQfEWOZx4EJ中提到的那样)。

package main

import (
    "flag"
    "testing"
)

var configFile = flag.String("config", "", "File containing configuration")

func getConfigFile() string {
    return *configFile
}

func TestConfig(t *testing.T) {
    want := "testconfig"
    if s := getConfigFile(); s != want {
        t.Errorf("Got %s, want %s", s, want)
    }
}

测试运行:

$ go test
--- FAIL: TestConfig (0.00s)
    flag_test.go:17: Got , want testconfig
FAIL
exit status 1
FAIL    github.com/dmitris/soflagtest   0.013s
$ go test -config testconfig
PASS
ok      github.com/dmitris/soflagtest   0.012s

您也可以使用 var configFile string声明和init()函数将标志值赋给变量:

func init() {
     flag.StringVar(&configFile, "config", "", "File containing configuration")
}

(然后在getConfigFile中没有指针解除引用,因为configFile是一个字符串)