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