Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test different flag values

I have the following Golang code:

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

This function is used elsewhere in my code, and I'd like to unit test what happens here when the user provides different values for the config argument (the config file name is used else where).
Is there a way to tell the flag package to return different values for the config argument while under test?

like image 545
Kurtis Nusbaum Avatar asked Aug 02 '16 04:08

Kurtis Nusbaum


1 Answers

I have found that for testing custom flags is better to create a custom flag set, in that way I can fully test the flags, including the -h option without exiting the tests. hope the attached code could give you and idea of how you could implement test on your code:

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

}

I put it also here: https://play.golang.org/p/h1nok1UMLA hope it can give you an idea.

like image 50
nbari Avatar answered Nov 12 '22 06:11

nbari