且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-02-21 09:10:23

自定义测试和处理标志可以通过 flag.Var 功能在 标志$ c $ c> 包。

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

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

  type Value接口{
String()string
Set(string)error
}

T这里是 example_test.go 档案中的 标记套件来源



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

 包主要

导入(
错误
标记
fmt


类型formatType字符串

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

func(f * formatType)Set值字符串)错误{
如果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:=`格式类型。必须是text,json或hash。 (& typeFlag,format,usage)
flag.Var(& typeFlag,f,用法+(简写))

$ b $ func main(){
flag.Parse()
fmt.Println(Format type is,typeFlag)
}

对于这样一个简单的例子来说,这可能是矫枉过正的,但在定义更复杂的标志类型时可能非常有用(链接的例子根据 time.Duration )将逗号分隔的间隔列表转换为自定义类型的片段。



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


I would like a unit test that verifies a particular command line flag is within an enumeration.

Here is the code I would like to write tests against:

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

The desired test would pass only if -format equalled one of the const values given above. This value would be available in formatType. An example correct call would be: program -format text

What is the best way to test the desired behaviors?

Note: Perhaps I have phrased this poorly, but the displayed code it not the unit test itself, but the code I want to write unit tests against. This is a simple example from the tool I am writing and wanted to ask if there were a good way to test valid inputs to the tool.

Custom testing and processing of flags can be achieved with the flag.Var function in the flag package.

Flag.Var "defines a flag with the specified name and usage string. The type and value of the flag are represented by the first argument, of type Value, which typically holds a user-defined implementation of Value."

A flag.Value is any type that satisfies the Value interface, defined as:

type Value interface {
    String() string
    Set(string) error
}

There is a good example in the example_test.go file in the flag package source

For your use case you could use something like:

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

This is probably overkill for such a simple example, but may be very useful when defining more complex flag types (The linked example converts a comma separated list of intervals into a slice of a custom type based on time.Duration).

EDIT: In answer to how to run unit tests against flags, the most canonical example is flag_test.go in the flag package source. The section related to testing custom flag variables starts at Line 181.