问题描述
工作需求,写了一个底层调用的方法,就想测一测这个接口别有什么问题,于是写了一个单元测试用例,试着跑了一下,就报了下面这个错误
flag provided but not defined: -test.v
单元测试代码:
func TestA(t *testing.T) {
type args struct {
ctx context.Context
key string
secret string
msg string
}
tests := []struct {
name string
args args
want []byte
wantErr bool
}{
{
name: "正常",
args: args{
ctx: context.Background(),
key: "key_test",
secret: "secret_test",
msg: "你好呀,小朋友",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := baseService.A(tt.args.ctx, tt.args.key, tt.args.secret, tt.args.msg)
if (err != nil) != tt.wantErr {
t.Errorf("A() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("A() got = %v, want %v", got, tt.want)
}
})
}
}
问题原因追溯
1. -test.v是testing包中定义的命令行参数,flag provided but not defined 是flag包的Parse()方法调用时抛的异常。
2. 测试代码中有引用自定义的参数命令行参数,再底层引用中找到了下面这段代码
var usr1 = flag.String("usr1", "", "user defined flag -usr1")
var usr2 = flag.String("usr2", "", "user defined flag -usr2")
var usr3 = flag.String("usr3", "", "user defined flag -usr3")
var usr4 = flag.String("usr4", "", "user defined flag -usr4")
var usr5 = flag.String("usr5", "", "user defined flag -usr5")
func init() {
if !flag.Parsed() {
flag.Parse()
}
}
init方法中定义的flag再运行中都有提示给出,猜测是init方法中调用的Parse方法调用时,testing中的命令行参数还没有被解析
3. 再看下Parse()方法的实现代码
s := f.args[0] //取执行时的命令行参数
name := s[numMinuses:] 命令行参数名称处理
m := f.formal 已初始化的命令行参数
flag, alreadythere := m[name]
if !alreadythere { //执行时带的命令行参数如果没有被初始化就报错
if name == "help" || name == "h" { // special case for nice help message.
f.usage()
return false, ErrHelp
}
return false, f.failf("flag provided but not defined: -%s", name)
}
4. 上面跑出的异常就是由3处的函数调用产生的,我们再确认下testing的命令行参数初始化代码
func Init() {
chatty = flag.Bool("test.v", false, "verbose: print additional output")
count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
}
func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
Init()
return &M{
deps: deps,
tests: tests,
benchmarks: benchmarks,
examples: examples,
}
}
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, examples).Run())
}
testing的命令行初始化实在运行时才开始的。所以可以确认是自定义包中的初始化函数中的flag.Parse()引起的。
问题解决
定位了问题之后,我们在测试用例中再手动引入testing.Init()方法,使其在引用了flag.Parse()包之前被初始化掉。
import (
"context"
"reflect"
"testing"
_ "app/test/init"
"app/service/baseService"
)
//app/test/init/init.go
import "testing"
func init(){
testing.Init()
}
再次运行测试用例,不再报错
image.png