效果
为go项目中每个go文件生成对应的test文件,为每个接口生成对应的单测接口。
类似于这样,为go项目中每个包都生成一个test文件,单测模板如下:
比如函数接口为func releaseEndpoint(instanceID string, endpointID string) error
生成的单测为:
准备工具
GitHub - cweill/gotests: Automatically generate Go test boilerplate from your source code.
下载命令:
$ go get -u github.com/cweill/gotests/...
使用方式(可以按照自己的想法设置):
Usage of gotests:
-all
generate tests for all functions and methods
-excl string
regexp. generate tests for functions and methods that don't match. Takes precedence over -only, -exported, and -all
-exported
generate tests for exported functions and methods. Takes precedence over -only and -all
-i print test inputs in error messages
-nosubtests
disable generating tests using the Go 1.7 subtests feature
-only string
regexp. generate tests for functions and methods that match only. Takes precedence over -all
-parallel
enable generating parallel subtests
-template string
optional. Specify custom test code templates, e.g. testify. This can also be set via environment variable GOTESTS_TEMPLATE
-template_dir string
optional. Path to a directory containing custom test code templates. Takes precedence over -template. This can also be set via environment variable GOTESTS_TEMPLATE_DIR
-template_params string
read external parameters to template by json with stdin
-template_params_file string
read external parameters to template by json with file
-w write output to (test) files instead of stdout
准备模板
gotests工具是会准备一套自用的模板的,位置在:gotests/internal/render/templates at develop · cweill/gotests · GitHub
比较重要的是function.tmpl,我们可以自定义,下面是我自用的,仅供参考
{{define "function"}}
{{- $f := .}}
func {{.TestName}}(t *testing.T) {
{{- with .Receiver}}
{{- if .IsStruct}}
{{- if .Fields}}
type fields struct {
{{- range .Fields}}
{{Field .}} {{.Type}}
{{- end}}
}
{{- end}}
{{- end}}
{{- end}}
{{- if .TestParameters}}
type args struct {
{{- range .TestParameters}}
{{Param .}} {{.Type}}
{{- end}}
}
{{- end}}
tests := []struct {
name string
{{- with .Receiver}}
{{- if and .IsStruct .Fields}}
fields fields
{{- else}}
{{Receiver .}} {{.Type}}
{{- end}}
{{- end}}
{{- if .TestParameters}}
args args
{{- end}}
{{- range .TestResults}}
{{Want .}} {{.Type}}
{{- end}}
{{- if .ReturnsError}}
wantErr bool
{{- end}}
}{
// TODO: Add test cases.
}
for {{if (or .Subtests (not .IsNaked))}} _, tt := {{end}} range tests {
{{- if .Parallel}}tt := tt{{end}}
mockey.PatchConvey(fmt.Sprintf("{{.TestName}}:%s", tt.name), t, func() {
{{- if .Parallel}}t.Parallel(){{end}}
// mock func here
// mockey.Mock(...).Return...).Build()
{{- with .Receiver}}
{{- if .IsStruct}}
{{Receiver .}} := {{if .Type.IsStar}}&{{end}}{{.Type.Value}}{
{{- range .Fields}}
{{.Name}}: tt.fields.{{Field .}},
{{- end}}
}
{{- end}}
{{- end}}
{{- range .Parameters}}
{{- if .IsWriter}}
{{Param .}} := &bytes.Buffer{}
{{- end}}
{{- end}}
{{- if and (not .OnlyReturnsError) (not .OnlyReturnsOneValue) }}
{{template "results" $f}} {{template "call" $f}}
{{- end}}
{{- if .ReturnsError}}
if {{if .OnlyReturnsError}} err := {{template "call" $f}}; {{end}} (err != nil) != tt.wantErr {
t.Errorf("{{template "message" $f}} error = %v, wantErr %v", {{template "inputs" $f}} err, tt.wantErr)
{{- if .TestResults}}
{{if .Subtests }}return{{else}}continue{{end}}
{{- end}}
}
{{- end}}
{{- range .TestResults}}
{{- if .IsWriter}}
if {{Got .}} := {{Param .}}.String(); {{Got .}} != tt.{{Want .}} {
{{- else if .IsBasicType}}
if {{if $f.OnlyReturnsOneValue}}{{Got .}} := {{template "inline" $f}}; {{end}} {{Got .}} != tt.{{Want .}} {
{{- else}}
if {{if $f.OnlyReturnsOneValue}}{{Got .}} := {{template "inline" $f}}; {{end}} !reflect.DeepEqual({{Got .}}, tt.{{Want .}}) {
{{- end}}
t.Errorf("{{template "message" $f}} {{if $f.ReturnsMultiple}}{{Got .}} {{end}}= %v, want %v", {{template "inputs" $f}} {{Got .}}, tt.{{Want .}})
}
{{- end}}
{{- if .Subtests }} }) {{- end -}}
}
}
{{end}}
go项目ut生成方式
$gotests -i -template_dir $templ_dir -all -w $file > /dev/null
其中templ_dir指的是模板绝对路径,file指的是想要生成ut的go文件。
针对整个项目
写一个sh脚本来进行遍历,筛选go文件并生成:
#!/usr/bin/env bash
# ===================================================================
# build ut test
# ===================================================================
pwd_dir=`pwd`
gotests=$pwd_dir/ut/gotests
templ_dir=$pwd_dir/ut/templates
# 跳过的文件
ignore_dir=(\
"$pwd_dir/ut" \
"$pwd_dir/output" \
"$pwd_dir/model" \
)
function is_ignore_dir(){
for i in ${ignore_dir[@]}
do
if [ $1 == $i ]
then
return 1
fi
done
return 0
}
function build_ut(){
if [ -d $1 ]
then
is_ignore_dir $1
if [ $? == 1 ]
then
return
fi
else
return
fi
# 生成ut test文件
go_file_list=(`ls $1|grep '.go' |grep -v '_test.go'`)
for file in ${go_file_list[@]}
do
$gotests -i -template_dir $templ_dir -all -w $1"/"$file > /dev/null
done
for file in `ls $1`
do
build_ut $1"/"$file
done
}
build_ut $pwd_dir
这里我还添加了需要忽视的文件夹的选项,可以自行添加,添加后会跳过,不再生成ut。
准备好脚本后,在自己的go项目中调用即可!!