> 文章列表 > 一键生成!如何为整个go项目自动添加单测

一键生成!如何为整个go项目自动添加单测

一键生成!如何为整个go项目自动添加单测

效果

为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[@]}doif [ $1 == $i ]thenreturn 1fidonereturn 0
}function build_ut(){if [ -d $1 ]thenis_ignore_dir $1if [ $? == 1 ]thenreturnfielsereturnfi# 生成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/nulldonefor file in `ls $1`dobuild_ut $1"/"$filedone
}build_ut $pwd_dir

这里我还添加了需要忽视的文件夹的选项,可以自行添加,添加后会跳过,不再生成ut。

准备好脚本后,在自己的go项目中调用即可!!