Open Zxilly opened 4 months ago
当然,反过来也是可以的。加一个MockWithGen之类的API,真正的实现放在生成的文件里
这些方式对代码都有侵入性。
之前我做过一个尝试,相对来说会简单一点,步骤如下:
go
的脚本(具体内容参考后面)脚本内容如下:
#!/usr/bin/env bash
# 去除PATH中的/tmp/xgo/bin
# 例如: PATH=/tmp/xgo/bin:/usr/bin -> PATH=:/usr/bin
PATH=${PATH/'tmp/xgo/bin'/}
case $1 in
build|test|run)
xgo "$@"
;;
*)
go "$@"
;;
esac
为了兼容不同的操作系统,这个脚本可以通过类似于 xgo tool setup-go
这样的命令来生成
之所以能够这样做的原因,是因为xgo build, test, run完全兼容go build ,test, run.
有侵入性不是问题吧,codegen的或多或少都有。生成的代码中可以引入xgo的真实实现,这样在CI上跑测试的时候就不用装xgo了。 而且这样可以把xgo的版本锁定在go.mod里。
我以为是每个用例都要生成,你说的是只需要生成一个文件吗?这样的话确实也没关系
我再描述一下我的想法吧
xxx_xgo_test.go
文件中,Impl 中起一个子进程调用xgo再次编译运行,这样就允许 TestXXX 直接被 go test 执行为了和标准的实现区分开,可以开一个 generate 子包,这个包提供一致的 API,但是依赖 codegen 运行
我再描述一下我的想法吧
- 只考虑 test
- 使用了 xgo 的 TestXXX,生成一个 TestXXXImpl 在同名的
xxx_xgo_test.go
文件中,Impl 中起一个子进程调用xgo再次编译运行,这样就允许 TestXXX 直接被 go test 执行- 使用了 xgo 的文件用 buildtag 隔离,不允许 go 编译,go 编译运行的实际上是 TestXXXImpl
比如说,greet_test.go
:
// +build xgo
//go:build xgo
package greet
import "github.com/xhd2015/xgo/runtime/mock"
func TestGreet(t *testing.T){
mock.Patch(greet, func(s string) string {
return "mock " + s
})
}
然后xgo生成greet_xgo_test.go
:
package greet
import "github.com/xhd2015/xgo/support/cmd"
func TestGreetImpl(t *testing.T){
err := cmd.Run("xgo", "test","-tags","xgo", "-v", "-run","TestGreet").Run()
if err !=nil {
t.Fatal(err)
}
}
是的,这是我的想法,但是显然有很多edge case要处理
这个看起来是每个测试都要有一个对应的TestXXXImpl,而且这些Impl基本都是调用xgo,只是test的名称不一样。
所以我觉得可以把逻辑放在xgo里,生成的函数里面直接从xgo调就好了
甚至可以说重写 TestMain 劫持命令行参数,不用每个 Test 都起子进程
如果只是为了达到使用go就能运行测试用例,我觉得前面我说的那种生成一个go脚本用来转发命令的方式更加透明一点。我可以提个PR验证一下
这个转发方式就是我之前提到的问题,处理不了coverage。特别是使用 GOCOVERDIR
环境变量控制的
看到了一些关于怎么和官方插件生态集成的讨论,设想了一种基于代码生成的方法。 对于每一个使用了 xgo 的测试,生成一个对应的 stub 测试,使用 xgo 本身的测试使用 build tag 隔离,从 stub 中起子进程或者其他的方式调用 xgo。 这个方案可能产生的问题应该是代码覆盖率会被这种情况影响,xgo 已经写入了覆盖率文件以后,go 本身又会再写入一次,我还没有想到怎么解决这个。