Open18

テストの時だけモックを入れたい

tenntenntenntenn

テストの時に-overlayフラグを指定すると、ソースコードを入れ替える。mocknnコマンドでOverlayJSONを生成する。

$ go test -overlay=`mocknn`
tenntenntenntenn

mocknnコマンドは静的解析を用いて対象のパッケージで定義された型のうち、//mocknn:ディレクティブコメントのついた型を探す。

//mocknn:UserRepoMock
type UserRepo struct {
    // 略
}
tenntenntenntenn

そして、型の定義をコメントディレクティブに書かれた型への型エイリアスに置き換える。

type UserRepo = UserRepoMock
tenntenntenntenn

型エイリアスされるモック型は_test.goに自由に記述する。テストのときのみビルドされる。

tenntenntenntenn

入れ替えたソースコードをtmpディレクトリに生成し、テストを実行する際に-overlayオプションで指定してテスト時にソースコードを入れ替える。

tenntenntenntenn

一連の流れをmocknn testコマンドにしても良いかもしれない。

tenntenntenntenn

go testに引き渡すオプションとmocknnが使用するオプションをわけたい。必須パラメータ(flag.Args相当)も取得したい。
事前にgo testのオプションがわかれば、それをすべてflagパッケージで登録しておけば良さそうだけど、buildfalgsやtestflagsもあるので大変。
testflagsはTestを動かしてみれば取得できる。
https://go.dev/play/p/gtbgv2h2Cp6

tenntenntenntenn

外部パッケージの置き換えをする場合、テスト対象のパッケージごとに入れ替えるソースコードを作る必要がある?

go test単位で動作する-overlayでは厳しそう。

tenntenntenntenn

TOOLEXEC_IMPORTPATHのように、-toolexecに指定したコマンドに情報を渡すなら、環境変数が良いかも知れない。

tenntenntenntenn
fmtパッケージのビルド
# fmt
TOOLEXEC_IMPORTPATH fmt
/usr/local/go/pkg/tool/darwin_amd64/compile
-o $WORK/b003/_pkg_.a
-trimpath /Users/tenntenn/repos/tenntenn/scrap/trytoolexc/_overlay/fmt.go=>/usr/local/go/src/fmt/doc.go;/var/folders/dr/gn16sh9935zcz37xt2ghpk480000gn/T/go-build2864553458/b003=>
-p fmt
-std
-complete
-buildid vW3Fjg5-Mb8KA51dmdmR/vW3Fjg5-Mb8KA51dmdmR
-goversion go1.18
-c=4
-nolocalimports
-importcfg $WORK/b003/importcfg
-pack
/Users/tenntenn/repos/tenntenn/scrap/trytoolexc/_overlay/fmt.go
/usr/local/go/src/fmt/errors.go /usr/local/go/src/fmt/format.go
/usr/local/go/src/fmt/print.go /usr/local/go/src/fmt/scan.go
tenntenntenntenn

テスト対象のパッケージごとにバイナリが生成される。パッケージaのテストの場合は、a.testみたいな。つまり、linkはバイナリごとにされる。

テストバイナリの生成(リンク)
# github.com/tenntenn/scrap/trytoolexec/b.test
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/b.test
/usr/local/go/pkg/tool/darwin_amd64/link
-o $WORK/b083/b.test
-importcfg $WORK/b083/importcfg.link
-s
-w
-buildmode=exe
-buildid=72NqY39MAur8nXs8zdTn/8VJcOmZcLruWf2ACx2J0/qflpWhgTKI1mU0sN4gvW/72NqY39MAur8nXs8zdTn
-extld=clang
$WORK/b083/_pkg_.a

# github.com/tenntenn/scrap/trytoolexec/a.test
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/a.test
/usr/local/go/pkg/tool/darwin_amd64/link
-o $WORK/b053/a.test
-importcfg $WORK/b053/importcfg.link
-s
-w
-buildmode=exe
-buildid=pkYZp2rZjTTPePp0UAOf/xGQvFK9Qom0rzR5PRmMM/S8NFlK9k5dhua8NF3fqF/pkYZp2rZjTTPePp0UAOf
-extld=clang
$WORK/b053/_pkg_.a
tenntenntenntenn
-toolexecで取得したコマンド
# github.com/tenntenn/scrap/trytoolexec/b
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/b
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b041/_pkg_.a -trimpath $WORK/b041=> -p github.com/tenntenn/scrap/trytoolexec/b -lang=go1.18 -complete -buildid E1q9GG9Uekl0mQ8YOUEL/E1q9GG9Uekl0mQ8YOUEL -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b041/importcfg -pack b/b.go

# fmt
TOOLEXEC_IMPORTPATH fmt
/usr/local/go/pkg/tool/darwin_amd64/compile
-o $WORK/b003/_pkg_.a
-trimpath /Users/tenntenn/repos/tenntenn/scrap/trytoolexc/_overlay/fmt.go=>/usr/local/go/src/fmt/doc.go;/var/folders/dr/gn16sh9935zcz37xt2ghpk480000gn/T/go-build2864553458/b003=> 
-p fmt 
-std 
-complete 
-buildid vW3Fjg5-Mb8KA51dmdmR/vW3Fjg5-Mb8KA51dmdmR 
-goversion go1.18 
-c=4 
-nolocalimports 
-importcfg $WORK/b003/importcfg 
-pack 
/Users/tenntenn/repos/tenntenn/scrap/trytoolexc/_overlay/fmt.go 
/usr/local/go/src/fmt/errors.go /usr/local/go/src/fmt/format.go 
/usr/local/go/src/fmt/print.go /usr/local/go/src/fmt/scan.go

# runtime/trace
TOOLEXEC_IMPORTPATH runtime/trace
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b051/_pkg_.a -trimpath $WORK/b051=> -p runtime/trace -std -buildid PxznaATDHPddicWeMzx2/PxznaATDHPddicWeMzx2 -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b051/importcfg -pack /usr/local/go/src/runtime/trace/annotation.go /usr/local/go/src/runtime/trace/trace.go
# github.com/tenntenn/scrap/trytoolexec/a
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/a
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b002/_pkg_.a -trimpath /Users/tenntenn/repos/tenntenn/scrap/trytoolexc/_overlay/a.go=>/Users/tenntenn/repos/tenntenn/scrap/trytoolexc/a/a.go;/var/folders/dr/gn16sh9935zcz37xt2ghpk480000gn/T/go-build2864553458/b002=> -p github.com/tenntenn/scrap/trytoolexec/a -lang=go1.18 -complete -buildid UMxYk0r5WcNCgqgj-NHL/UMxYk0r5WcNCgqgj-NHL -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b002/importcfg -pack /Users/tenntenn/repos/tenntenn/scrap/trytoolexc/_overlay/a.go
# github.com/tenntenn/scrap/trytoolexec/cmd/mytool
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/cmd/mytool
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b085/_pkg_.a -trimpath $WORK/b085=> -p main -lang=go1.18 -complete -buildid xPfZK5-Yzad5OJuX-m0A/xPfZK5-Yzad5OJuX-m0A -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b085/importcfg -pack cmd/mytool/main.go
# go/token
TOOLEXEC_IMPORTPATH go/token
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b068/_pkg_.a -trimpath $WORK/b068=> -p go/token -std -complete -buildid E_vkcgURVM9fTDsO89oL/E_vkcgURVM9fTDsO89oL -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b068/importcfg -pack /usr/local/go/src/go/token/position.go /usr/local/go/src/go/token/serialize.go /usr/local/go/src/go/token/token.go
# github.com/tenntenn/scrap/trytoolexec
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b001/_pkg_.a -trimpath $WORK/b001=> -p main -lang=go1.18 -complete -buildid ree-9indHNzQNG4iHYuq/ree-9indHNzQNG4iHYuq -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b001/importcfg -pack ./main.go
?   	github.com/tenntenn/scrap/trytoolexec	[no test files]
# runtime/debug
TOOLEXEC_IMPORTPATH runtime/debug
/usr/local/go/pkg/tool/darwin_amd64/asm -p runtime/debug -trimpath $WORK/b050=> -I $WORK/b050/ -I /usr/local/go/pkg/include -D GOOS_darwin -D GOARCH_amd64 -D GOAMD64_v1 -gensymabis -o $WORK/b050/symabis /usr/local/go/src/runtime/debug/debug.s
# runtime/debug
TOOLEXEC_IMPORTPATH runtime/debug
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b050/_pkg_.a -trimpath $WORK/b050=> -p runtime/debug -std -buildid IQybzADWXTOuXjbL35-P/IQybzADWXTOuXjbL35-P -goversion go1.18 -symabis $WORK/b050/symabis -c=4 -nolocalimports -importcfg $WORK/b050/importcfg -pack -asmhdr $WORK/b050/go_asm.h /usr/local/go/src/runtime/debug/garbage.go /usr/local/go/src/runtime/debug/mod.go /usr/local/go/src/runtime/debug/stack.go /usr/local/go/src/runtime/debug/stubs.go
# runtime/debug
TOOLEXEC_IMPORTPATH runtime/debug
/usr/local/go/pkg/tool/darwin_amd64/asm -p runtime/debug -trimpath $WORK/b050=> -I $WORK/b050/ -I /usr/local/go/pkg/include -D GOOS_darwin -D GOARCH_amd64 -D GOAMD64_v1 -o $WORK/b050/debug.o /usr/local/go/src/runtime/debug/debug.s
# flag
TOOLEXEC_IMPORTPATH flag
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b045/_pkg_.a -trimpath $WORK/b045=> -p flag -std -complete -buildid SDKIg1Ifg3v7dzen3h3S/SDKIg1Ifg3v7dzen3h3S -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b045/importcfg -pack /usr/local/go/src/flag/flag.go
# go/scanner
TOOLEXEC_IMPORTPATH go/scanner
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b067/_pkg_.a -trimpath $WORK/b067=> -p go/scanner -std -complete -buildid xoj6EfjHmcD5WlMn7fPH/xoj6EfjHmcD5WlMn7fPH -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b067/importcfg -pack /usr/local/go/src/go/scanner/errors.go /usr/local/go/src/go/scanner/scanner.go
# compress/flate
TOOLEXEC_IMPORTPATH compress/flate
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b079/_pkg_.a -trimpath $WORK/b079=> -p compress/flate -std -complete -buildid mMMtWGvr3hm4pzY3R8rm/mMMtWGvr3hm4pzY3R8rm -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b079/importcfg -pack /usr/local/go/src/compress/flate/deflate.go /usr/local/go/src/compress/flate/deflatefast.go /usr/local/go/src/compress/flate/dict_decoder.go /usr/local/go/src/compress/flate/huffman_bit_writer.go /usr/local/go/src/compress/flate/huffman_code.go /usr/local/go/src/compress/flate/inflate.go /usr/local/go/src/compress/flate/token.go
# compress/gzip
TOOLEXEC_IMPORTPATH compress/gzip
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b078/_pkg_.a -trimpath $WORK/b078=> -p compress/gzip -std -complete -buildid BUG2zASMdYSvXJu52YD6/BUG2zASMdYSvXJu52YD6 -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b078/importcfg -pack /usr/local/go/src/compress/gzip/gunzip.go /usr/local/go/src/compress/gzip/gzip.go
# encoding/json
TOOLEXEC_IMPORTPATH encoding/json
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b062/_pkg_.a -trimpath $WORK/b062=> -p encoding/json -std -complete -buildid Qxl-hGqssB1JJe-CC_yT/Qxl-hGqssB1JJe-CC_yT -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b062/importcfg -pack /usr/local/go/src/encoding/json/decode.go /usr/local/go/src/encoding/json/encode.go /usr/local/go/src/encoding/json/fold.go /usr/local/go/src/encoding/json/indent.go /usr/local/go/src/encoding/json/scanner.go /usr/local/go/src/encoding/json/stream.go /usr/local/go/src/encoding/json/tables.go /usr/local/go/src/encoding/json/tags.go
# runtime/pprof
TOOLEXEC_IMPORTPATH runtime/pprof
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b077/_pkg_.a -trimpath $WORK/b077=> -p runtime/pprof -std -buildid CTGY3zUQyYamfX98UhFZ/CTGY3zUQyYamfX98UhFZ -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b077/importcfg -pack /usr/local/go/src/runtime/pprof/elf.go /usr/local/go/src/runtime/pprof/label.go /usr/local/go/src/runtime/pprof/map.go /usr/local/go/src/runtime/pprof/pprof.go /usr/local/go/src/runtime/pprof/pprof_rusage.go /usr/local/go/src/runtime/pprof/proto.go /usr/local/go/src/runtime/pprof/protobuf.go /usr/local/go/src/runtime/pprof/protomem.go /usr/local/go/src/runtime/pprof/runtime.go
# go/ast
TOOLEXEC_IMPORTPATH go/ast
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b066/_pkg_.a -trimpath $WORK/b066=> -p go/ast -std -complete -buildid iF9ZL3v6MmtfhvNPdROf/iF9ZL3v6MmtfhvNPdROf -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b066/importcfg -pack /usr/local/go/src/go/ast/ast.go /usr/local/go/src/go/ast/commentmap.go /usr/local/go/src/go/ast/filter.go /usr/local/go/src/go/ast/import.go /usr/local/go/src/go/ast/print.go /usr/local/go/src/go/ast/resolve.go /usr/local/go/src/go/ast/scope.go /usr/local/go/src/go/ast/walk.go
# testing
TOOLEXEC_IMPORTPATH testing
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b043/_pkg_.a -trimpath $WORK/b043=> -p testing -std -complete -buildid srCcLNO5oNrweZMJo3HT/srCcLNO5oNrweZMJo3HT -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b043/importcfg -pack /usr/local/go/src/testing/allocs.go /usr/local/go/src/testing/benchmark.go /usr/local/go/src/testing/cover.go /usr/local/go/src/testing/example.go /usr/local/go/src/testing/fuzz.go /usr/local/go/src/testing/match.go /usr/local/go/src/testing/run_example.go /usr/local/go/src/testing/testing.go /usr/local/go/src/testing/testing_other.go
# go/internal/typeparams
TOOLEXEC_IMPORTPATH go/internal/typeparams
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b070/_pkg_.a -trimpath $WORK/b070=> -p go/internal/typeparams -std -complete -buildid kX6DGnkKwC2kazthfXbX/kX6DGnkKwC2kazthfXbX -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b070/importcfg -pack /usr/local/go/src/go/internal/typeparams/common.go /usr/local/go/src/go/internal/typeparams/typeparams.go
# github.com/tenntenn/scrap/trytoolexec/b [github.com/tenntenn/scrap/trytoolexec/b.test]
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/b [github.com/tenntenn/scrap/trytoolexec/b.test]
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b082/_pkg_.a -trimpath $WORK/b082=> -p github.com/tenntenn/scrap/trytoolexec/b -lang=go1.18 -complete -buildid PUiFLhA4eix53jtUJSmH/PUiFLhA4eix53jtUJSmH -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b082/importcfg -pack b/b.go b/b_test.go

# github.com/tenntenn/scrap/trytoolexec/a [github.com/tenntenn/scrap/trytoolexec/a.test]
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/a [github.com/tenntenn/scrap/trytoolexec/a.test]
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b042/_pkg_.a -trimpath /Users/tenntenn/repos/tenntenn/scrap/trytoolexc/_overlay/a.go=>/Users/tenntenn/repos/tenntenn/scrap/trytoolexc/a/a.go;/var/folders/dr/gn16sh9935zcz37xt2ghpk480000gn/T/go-build2864553458/b042=> -p github.com/tenntenn/scrap/trytoolexec/a -lang=go1.18 -complete -buildid nj4EZWyjrpch5N-RDwdj/nj4EZWyjrpch5N-RDwdj -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b042/importcfg -pack /Users/tenntenn/repos/tenntenn/scrap/trytoolexc/_overlay/a.go a/a_test.go

# go/parser
TOOLEXEC_IMPORTPATH go/parser
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b069/_pkg_.a -trimpath $WORK/b069=> -p go/parser -std -complete -buildid MqJQVoVwxpkr7CbS6ifT/MqJQVoVwxpkr7CbS6ifT -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b069/importcfg -pack /usr/local/go/src/go/parser/interface.go /usr/local/go/src/go/parser/parser.go /usr/local/go/src/go/parser/resolver.go
# internal/fuzz
TOOLEXEC_IMPORTPATH internal/fuzz
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b057/_pkg_.a -trimpath $WORK/b057=> -p internal/fuzz -std -complete -buildid 6OgWmqJPYj9Y_N7835-N/6OgWmqJPYj9Y_N7835-N -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b057/importcfg -pack /usr/local/go/src/internal/fuzz/counters_supported.go /usr/local/go/src/internal/fuzz/coverage.go /usr/local/go/src/internal/fuzz/encoding.go /usr/local/go/src/internal/fuzz/fuzz.go /usr/local/go/src/internal/fuzz/mem.go /usr/local/go/src/internal/fuzz/minimize.go /usr/local/go/src/internal/fuzz/mutator.go /usr/local/go/src/internal/fuzz/mutators_byteslice.go /usr/local/go/src/internal/fuzz/pcg.go /usr/local/go/src/internal/fuzz/queue.go /usr/local/go/src/internal/fuzz/sys_posix.go /usr/local/go/src/internal/fuzz/trace.go /usr/local/go/src/internal/fuzz/worker.go
# testing/internal/testdeps
TOOLEXEC_IMPORTPATH testing/internal/testdeps
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b055/_pkg_.a -trimpath $WORK/b055=> -p testing/internal/testdeps -std -complete -buildid oe9-2bqEk--4oiWNwkoE/oe9-2bqEk--4oiWNwkoE -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b055/importcfg -pack /usr/local/go/src/testing/internal/testdeps/deps.go
# github.com/tenntenn/scrap/trytoolexec/b.test
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/b.test
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b083/_pkg_.a -trimpath $WORK/b083=> -p main -lang=go1.18 -complete -buildid 8VJcOmZcLruWf2ACx2J0/8VJcOmZcLruWf2ACx2J0 -dwarf=false -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b083/importcfg -pack $WORK/b083/_testmain.go

# github.com/tenntenn/scrap/trytoolexec/a.test
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/a.test
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b053/_pkg_.a -trimpath $WORK/b053=> -p main -lang=go1.18 -complete -buildid xGQvFK9Qom0rzR5PRmMM/xGQvFK9Qom0rzR5PRmMM -dwarf=false -goversion go1.18 -c=4 -nolocalimports -importcfg $WORK/b053/importcfg -pack $WORK/b053/_testmain.go

# github.com/tenntenn/scrap/trytoolexec/b.test
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/b.test
/usr/local/go/pkg/tool/darwin_amd64/link
-o $WORK/b083/b.test
-importcfg $WORK/b083/importcfg.link
-s
-w
-buildmode=exe
-buildid=72NqY39MAur8nXs8zdTn/8VJcOmZcLruWf2ACx2J0/qflpWhgTKI1mU0sN4gvW/72NqY39MAur8nXs8zdTn
-extld=clang
$WORK/b083/_pkg_.a

# github.com/tenntenn/scrap/trytoolexec/a.test
TOOLEXEC_IMPORTPATH github.com/tenntenn/scrap/trytoolexec/a.test
/usr/local/go/pkg/tool/darwin_amd64/link 
-o $WORK/b053/a.test 
-importcfg $WORK/b053/importcfg.link 
-s 
-w 
-buildmode=exe 
-buildid=pkYZp2rZjTTPePp0UAOf/xGQvFK9Qom0rzR5PRmMM/S8NFlK9k5dhua8NF3fqF/pkYZp2rZjTTPePp0UAOf 
-extld=clang 
$WORK/b053/_pkg_.a

ok  	github.com/tenntenn/scrap/trytoolexec/a	0.227s
ok  	github.com/tenntenn/scrap/trytoolexec/b	0.121s
?   	github.com/tenntenn/scrap/trytoolexec/cmd/mytool	[no test files]

tenntenntenntenn

linkで使われていない.aファイルはどうやってlinkに反映されているのか?
importcfgに.aのリストが書かれている?

tenntenntenntenn
packagefile fmt=/var/folders/dr/gn16sh9935zcz37xt2ghpk480000gn/T/go-build2413945521/b003/_pkg_.a 

このパスを入れ替えれば行けそう。