如何在Go中单元测试命令行标志?

Kev*_*Dog 10 unit-testing go

我想要一个单元测试来验证特定命令行标志是否在枚举中.

这是我想编写测试的代码:

var formatType string

const (
    text = "text"
    json = "json"
    hash = "hash"
)

func init() {
    const (
        defaultFormat = "text"
        formatUsage   = "desired output format"
    )

    flag.StringVar(&formatType, "format", defaultFormat, formatUsage)
    flag.StringVar(&formatType, "f", defaultFormat, formatUsage+" (shorthand)")

}

func main() {
    flag.Parse()
}
Run Code Online (Sandbox Code Playgroud)

只有当-format等于上面给出的一个const值时,所需的测试才会通过.此值可在formatType中使用.一个正确的调用示例是:program -format text

测试所需行为的最佳方法是什么?

注意:也许我的措辞很差,但显示的代码不是单元测试本身,而是我想编写单元测试的代码.这是我正在编写的工具中的一个简单示例,并且想要询问是否有一种很好的方法来测试该工具的有效输入.

Int*_*net 11

可以使用包中的flag.Var功能来实现标志的定制测试和处理flag.

Flag.Var "定义具有指定名称和用法字符串的标志.标志的类型和值由第一个参数表示,类型为Value,它通常包含用户定义的Value实现."

A flag.Value是满足Value接口的任何类型,定义如下:

type Value interface {
    String() string
    Set(string) error
}
Run Code Online (Sandbox Code Playgroud)

包源中的example_test.go文件中有一个很好的示例flag

对于您的用例,您可以使用以下内容:

package main

import (
    "errors"
    "flag"
    "fmt"
)

type formatType string

func (f *formatType) String() string {
    return fmt.Sprint(*f)
}

func (f *formatType) Set(value string) error {
    if len(*f) > 0 && *f != "text" {
        return errors.New("format flag already set")
    }
    if value != "text" && value != "json" && value != "hash" {
        return errors.New("Invalid Format Type")
    }
    *f = formatType(value)
    return nil
}

var typeFlag formatType

func init() {
    typeFlag = "text"
    usage := `Format type. Must be "text", "json" or "hash". Defaults to "text".`
    flag.Var(&typeFlag, "format", usage)
    flag.Var(&typeFlag, "f", usage+" (shorthand)")
}

func main() {
    flag.Parse()
    fmt.Println("Format type is", typeFlag)
}
Run Code Online (Sandbox Code Playgroud)

这可能是这样一个简单的例子矫枉过正,但限定更复杂的标志类型(链接的一例的逗号分隔的时间间隔的列表转换成基于自定义类型的切片时,可能是非常有用的time.Duration).

编辑:在回答如何针对标志运行单元测试时,最典型的例子是flag_test.go在标志包源中.与测试自定义标志变量相关的部分从第181行开始.


nem*_*emo 1

我不确定我们是否同意“单元测试”这个术语。在我看来,你想要实现的目标更像是程序中的一个非常正常的测试。您可能想做这样的事情:

func main() {
    flag.Parse()

    if formatType != text || formatType != json || formatType != hash {
        flag.Usage()
        return
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

遗憾的是,用自己的值验证器扩展标志解析器并不容易,因此您现在必须坚持这一点。

请参阅 Internet 以获取定义自定义格式类型及其验证器的解决方案。