Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

基于代码生成来 proxy go test 到 xgo #221

Open
Zxilly opened this issue Jun 23, 2024 · 15 comments
Open

基于代码生成来 proxy go test 到 xgo #221

Zxilly opened this issue Jun 23, 2024 · 15 comments
Labels
IDE Integration proposal Proposal new ideas
Milestone

Comments

@Zxilly
Copy link

Zxilly commented Jun 23, 2024

看到了一些关于怎么和官方插件生态集成的讨论,设想了一种基于代码生成的方法。
对于每一个使用了 xgo 的测试,生成一个对应的 stub 测试,使用 xgo 本身的测试使用 build tag 隔离,从 stub 中起子进程或者其他的方式调用 xgo。
这个方案可能产生的问题应该是代码覆盖率会被这种情况影响,xgo 已经写入了覆盖率文件以后,go 本身又会再写入一次,我还没有想到怎么解决这个。

@Zxilly
Copy link
Author

Zxilly commented Jun 23, 2024

当然,反过来也是可以的。加一个MockWithGen之类的API,真正的实现放在生成的文件里

@xhd2015
Copy link
Owner

xhd2015 commented Jun 24, 2024

这些方式对代码都有侵入性。

之前我做过一个尝试,相对来说会简单一点,步骤如下:

  • 创建一个临时目录: /tmp/xgo/bin
  • 在这个临时目录下创建一个名称为go的脚本(具体内容参考后面)
  • 在IDEA或VSCode中,将/tmp/xgo/bin加入到PATH中
  • 该脚本被调用的时候,检测子命令
    • 如果命令是 build, test, run, 则转发给xgo
    • 如果是其他命令,则将它们转发给原始的go程序
  • 转发之前,需要先将PATH中 /tmp/xgo/bin清除掉,避免干扰原始的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

@xhd2015
Copy link
Owner

xhd2015 commented Jun 24, 2024

为了兼容不同的操作系统,这个脚本可以通过类似于 xgo tool setup-go这样的命令来生成

@xhd2015
Copy link
Owner

xhd2015 commented Jun 24, 2024

之所以能够这样做的原因,是因为xgo build, test, run完全兼容go build ,test, run.

@xhd2015 xhd2015 added the proposal Proposal new ideas label Jun 24, 2024
@xhd2015 xhd2015 added this to the v1.1.0 milestone Jun 24, 2024
@Zxilly
Copy link
Author

Zxilly commented Jun 24, 2024

有侵入性不是问题吧,codegen的或多或少都有。生成的代码中可以引入xgo的真实实现,这样在CI上跑测试的时候就不用装xgo了。
而且这样可以把xgo的版本锁定在go.mod里。

@xhd2015
Copy link
Owner

xhd2015 commented Jun 24, 2024

我以为是每个用例都要生成,你说的是只需要生成一个文件吗?这样的话确实也没关系

@Zxilly
Copy link
Author

Zxilly commented Jun 24, 2024

我再描述一下我的想法吧

  • 只考虑 test
  • 使用了 xgo 的 TestXXX,生成一个 TestXXXImpl 在同名的 xxx_xgo_test.go 文件中,Impl 中起一个子进程调用xgo再次编译运行,这样就允许 TestXXX 直接被 go test 执行
  • 使用了 xgo 的文件用 buildtag 隔离,不允许 go 编译,go 编译运行的实际上是 TestXXXImpl

@Zxilly
Copy link
Author

Zxilly commented Jun 24, 2024

为了和标准的实现区分开,可以开一个 generate 子包,这个包提供一致的 API,但是依赖 codegen 运行

@xhd2015
Copy link
Owner

xhd2015 commented Jun 25, 2024

我再描述一下我的想法吧

  • 只考虑 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)
    }
}

@Zxilly
Copy link
Author

Zxilly commented Jun 25, 2024

是的,这是我的想法,但是显然有很多edge case要处理

@xhd2015
Copy link
Owner

xhd2015 commented Jun 25, 2024

这个看起来是每个测试都要有一个对应的TestXXXImpl,而且这些Impl基本都是调用xgo,只是test的名称不一样。

@Zxilly
Copy link
Author

Zxilly commented Jun 25, 2024

所以我觉得可以把逻辑放在xgo里,生成的函数里面直接从xgo调就好了

@Zxilly
Copy link
Author

Zxilly commented Jun 25, 2024

甚至可以说重写 TestMain 劫持命令行参数,不用每个 Test 都起子进程

@xhd2015
Copy link
Owner

xhd2015 commented Jun 25, 2024

如果只是为了达到使用go就能运行测试用例,我觉得前面我说的那种生成一个go脚本用来转发命令的方式更加透明一点。我可以提个PR验证一下

@Zxilly
Copy link
Author

Zxilly commented Jun 25, 2024

这个转发方式就是我之前提到的问题,处理不了coverage。特别是使用 GOCOVERDIR 环境变量控制的

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
IDE Integration proposal Proposal new ideas
Projects
Status: No status
Development

No branches or pull requests

2 participants