こんにちわ
ゴリラです
Goでテストを書く時、コマンドライン引数に任意の値を渡したい事があったので、
そのやり方をメモとして残しておきます。
flag引数
Goでは -arg value
という感じで、flagパッケージ引数を定義することができます。
var (
name = flag.String("name", "gorilla", "your name")
age = flag.Int("age", 10, "your age")
isHuman = flag.Bool("isHuman", false, "are your human?")
)
func echo() string {
return fmt.Sprintf("your status: name:%s, age:%d, isHuman:%v", *name, *age, *isHuman)
}
やり方
この引数の値をテスト時に任意の変更して、分岐を網羅したいときがあります。
そういった場合は、flagパッケージで用意されている flag.CommandLine.Set
関数を使うことで、
任意の値をセットすることができます。
func TestEcho(t *testing.T) {
tests := []struct {
name string
age string
isHuman string
want string
}{
{name: "gorilla", age: "26", isHuman: "false", want: "your status: name:gorilla, age:26, isHuman:false"},
{name: "dog", age: "10", isHuman: "false", want: "your status: name:dog, age:10, isHuman:false"},
{name: "bob", age: "30", isHuman: "true", want: "your status: name:bob, age:30, isHuman:true"},
}
for _, test := range tests {
flag.CommandLine.Set("name", test.name)
flag.CommandLine.Set("age", test.age)
flag.CommandLine.Set("isHuman", test.isHuman)
got := echo()
if test.want != got {
t.Fatalf("want %s, but got %s", test.want, got)
}
}
}
CommandLine.Set
の引数は key
と value
があり、ともにstringですが、
value
は内部でよしなに型変換してくれるので、intやboolも全てはstringで渡す必要があります。
まとめ
flag引数とそれ以外の引数をまとめて持っているのが flag.FlagSet
という構造体です。
type FlagSet struct {
// Usage is the function called when an error occurs while parsing flags.
// The field is a function (not a method) that may be changed to point to
// a custom error handler. What happens after Usage is called depends
// on the ErrorHandling setting; for the command line, this defaults
// to ExitOnError, which exits the program after calling Usage.
Usage func()
name string
parsed bool
actual map[string]*Flag
formal map[string]*Flag
args []string // arguments after flags
errorHandling ErrorHandling
output io.Writer // nil means stderr; use out() accessor
}
args
がflag引数以外の引数が入り、 formal
がflag引数が入っています。
深くは読んでいないのですが、interfaceを使用して、valueをparseしたりしているので、
シンプルだけど勉強になりそうなので、興味ある方はソースを読んでみてください。