2016-08-02 108 views
4

我有以下Golang代码:单元测试不同的标志值

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

此功能在我的代码用于其他地方,我想单元测试什么,当用户提供了不同的值发生在这里config参数(配置文件名在其他地方使用)。
有没有办法告诉标记包在测试时为config参数返回不同的值?

+4

不,没有。只需将你的函数分割成a)未经过单元测试的标志解析和b)加载配置文件 – Volker

回答

0

如果您更改它像下面的代码,go test将失败,但go test -config testconfig将通过。不是我们不需要在init()中调用flag.Parse(),因为它被测试包调用(如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是一个字符串)

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希望它可以给你出个主意。