Go语言 为单元测试重置高尔夫标志

zd287kbt  于 12个月前  发布在  Go
关注(0)|答案(3)|浏览(146)

我有一个go函数,它使用flag包来解析命令行参数。我想为参数和值的各种组合编写单元测试,但我遇到了这个问题。我可以运行任何一个测试来测试函数,但当我运行一组测试时,我在第二次调用函数时得到一个错误:“flag redefined”。
有没有办法重置flag包,这样当我用相同的arg名称第二次调用flag.StringVar()时,就不会出现“flag redefined”错误了?
编辑:我正在添加一个演示错误的代码示例。(这不是真实的代码结构.在真实的代码中,功能分布在生产代码、单元测试函数和重置函数中。)

func broken() {
    var debug bool
    flag.BoolVar(&debug, "debug", false, "enable debug")
    flag.Parse()

    flag.CommandLine.VisitAll(func(f *flag.Flag) {
        if f.Value != nil {
            f.Value.Set(f.DefValue)
        }
    })

    // Error occurs here when BoolVar is called with the 
    // same "debug" string.
    flag.BoolVar(&debug, "debug", false, "enable debug")
    flag.Parse()
}

字符串
实际上,代码看起来像这样:

type cmdArgs struct {
    debug bool,
    file  string,
}

func main() {
   args, err := parseArgs()
   if err != nil {
        // bail!!
   }
}

func parseArgs() (cmdArgs, error) {
    var debug bool
    var file string
    flag.BoolVar(&debug, "debug", false, "enable debug")
    flag.StringVar(&file, "file", "", "input file")
    flag.Parse()

    if "" == file {
        return cmdArgs{}, errors.New("--file is required.")
    }
    return cmdArgs{
        debug:   debug,
        file:    file,
    }, nil
}


单元测试看起来像这样:

func TestParseArgs_noFileArg(t *testing.T) {
    resetArgs()
    args, err := parseArgs()

    assert.Error(t, err, "error expected, none returned-- 
       file arg not provided, but required.") 
}

func TestParseArgs_withFileArg(t *testing.T) {
    resetArgs()
    os.Args = append(os.Args, "-file")
    os.Args = append(os.Args, "./input.json")
    args, err := parseArgs()

    assert.NoError(t, err, "Unexpected error")
    assert.Equal(t, "input.json", args.file, 
       "args.file value was incorrect.")
}

func resetArgs() {
    flag.CommandLine.VisitAll(func(f *flag.Flag) {
        if f.Value != nil {
            f.Value.Set(f.DefValue)
        }
    })
}

nkoocmlb

nkoocmlb1#

定义标志一次,并在每次测试中重用。
选项1:使用包级变量。

var debugFlag = flag.Bool("debug", false, "enable debug")
var fileFlag = flag.String("file", "", "input file")

func parseArgs() (cmdArgs, error) {
    flag.Parse()

    if "" == *fileFlag {
        return cmdArgs{}, errors.New("--file is required.")
    }
    return cmdArgs{
        debug: *debugFlag,
        file:  *fileFlag,
    }, nil
}

字符串
选项2:使用闭包。

var parseArgs = func() func() (cmdArgs, error) {
    var debug bool
    var file string
    flag.BoolVar(&debug, "debug", false, "enable debug")
    flag.StringVar(&file, "file", "", "input file")
    return func() (cmdArgs, error) {
        flag.Parse()

        if "" == file {
            return cmdArgs{}, errors.New("--file is required.")
        }
        return cmdArgs{
            debug: debug,
            file:  file,
        }, nil
    }
}()


无法从标志集中清除标志定义。

roejwanj

roejwanj2#

在每个测试中将命令行标志设置为新设置。

func TestParseArgs_noFileArg(t *testing.T) {
    flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
    args, err := parseArgs()
    assert.Error(t, err, "error expected, none returned-- 
       file arg not provided, but required.") 
}

字符串

7xzttuei

7xzttuei3#

如果你想针对一组固定的标志定义测试不同的命令行参数,那么请执行以下操作:
编写一个函数来重置命令行标志并解析新标志:

func resetAndParse(args ...string) {
    flag.CommandLine.VisitAll(func(f *flag.Flag) {
        if f.Value != nil {
            f.Value.Set(f.DefValue)
        }
    })
    flag.CommandLine.Parse(args)
}

字符串
定义标志一次,并在每次测试中重复使用:

// Define flag once for all tests.
var debug bool
flag.BoolVar(&debug, "debug", false, "enable debug")

// Test with debug flag set
resetAndParse("-debug")
fmt.Println("debug is", debug)

// Test with debug flag omitted
resetAndParse()
fmt.Println("debug is", debug)


https://go.dev/play/p/Y6uZD5JTyTs

相关问题