无法生成go覆盖率文件
我在本文中尝试运行了一个系统测试: 因此,请遵循提示 首先,我创建一个名为main_test.go的系统测试文件,如下所示:无法生成go覆盖率文件,go,test-coverage,Go,Test Coverage,我在本文中尝试运行了一个系统测试: 因此,请遵循提示 首先,我创建一个名为main_test.go的系统测试文件,如下所示: func TestSystem(t *testing.T) { t.Logf("systemtest mod=%v", *SystemTest) if *SystemTest { t.Log("runing system test....") main() } } 当执行此单元测试时,将执行整个主功能 然后我构建
func TestSystem(t *testing.T) {
t.Logf("systemtest mod=%v", *SystemTest)
if *SystemTest {
t.Log("runing system test....")
main()
}
}
当执行此单元测试时,将执行整个主功能
然后我构建了一个测试数据库:
go test -c -covermode=count -coverpkg ./... -o main.test
并在我的测试环境中执行测试二进制文件
./main.test -systemTest -test.coverprofile ./coverage.cov
因为程序将侦听并等待客户端的请求,所以除非我退出Manual,否则它不会退出,这意味着coverprofile不会被删除
所以我启动了一个计时器在15秒后停止程序。。。
但是,当程序退出时,coverprofile仍然没有被初始化
如果测试未调用main,则coverprofile可以正常运行
请参见主要功能
var mkrtExitWait sync.WaitGroup
var mkrtExitCode int
var mkrtRunning bool = false
func MKrtRun() int {
mkrtExitWait.Add(1)
mkrtRunning = true
mkrtExitWait.Wait()
return mkrtExitCode
}
func MKrtExit(code int) {
if !mkrtRunning {
os.Exit(code)
} else {
mkrtRunning = false
mkrtExitCode = code
mkrtExitWait.Done()
}
}
func main() {
// listen and serve code
......
if *SystemTest { // a command flag
go func(){
time.Sleep(time.Second * 10)
MKrtExit(0)
}()
}
MKrtRun()
}
我尝试了以下几种方法来生成覆盖率文件,但不起作用:
如何生成覆盖率文件?系统测试通常在您的测试上运行一些外部测试时使用 这意味着您需要修改主程序以退出某些Intrupts。SIGINT是主程序退出的最合适的信号,因为它符合POSIX信号 这可以通过添加以下内容来实现
// Handle graceful shutdown of http server via OS Interrupt
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt)
// Block a goroutine on Interrupt channel and close
// http server to exit gracefully
go func() {
<-quit
log.Info("receive interrupt signal")
MKrtEixt(0)
}()
//通过操作系统中断处理http服务器的正常关闭
退出:=接通(切换操作信号)
信号通知(退出,操作系统中断)
//在中断通道上阻塞goroutine并关闭
//http服务器正常退出
go func(){
我找到了coverprofile无法进行分级的原因
主协同程序由测试二进制文件启动,它将等待所有测试任务完成,最后生成覆盖文件。
主功能测试是其中一项任务,所以若主功能执行os.Exit(0),覆盖率文件将不会被删除。
在我的测试程序中,当主功能测试任务结束时,还有一些其他测试任务要执行,其中一个任务被I/O事件阻塞,没有超时,因此它与主功能测试任务无关。OP暗示了答案,但没有给出答案。关键是为了编写覆盖率配置文件n程序需要将执行返回到TestMain
,不能只调用os.Exit(0)
因此,真正需要做的就是使用主goroutine中的返回
来处理代码。下面是示例代码,它在编译测试二进制文件后使用:
go test-c-covermode=count-cover-coverpkg./…
然后它是这样运行的(在Windows上的powershell中需要引号,但在cmd中不需要):
testmain.test.exe“-test.coverprofile”coverage.cov systemTest
我发现,出于某种原因,仅当我的自定义标志systemTest
位于-test.coverprofile cov
之后时,才会生成覆盖率文件。下面是一个简单的示例:
main.go:
func main() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
done := make(chan struct{})
go func() {
<-c
done <- struct{}{}
}()
go func() {
for {
// this is where your real program runs
fmt.Println("printing and sleeping")
time.Sleep(1 * time.Second)
}
}()
<-done
return
}
灵感:
而为我解决这个问题的是旗帜顺序(作为@darkwing答案的一部分提到)
当我首先放置-test.coverprofile=coverage.cov
时,它工作了,并且创建了coverage.cov文件
注意:我必须在标志名和值之间添加=
符号
另外,我不需要在不同的go例程中运行它。不要运行已编译的测试二进制文件,而是让go test-cover
来做这项工作。@Volker我的编译环境和测试环境在两台不同的机器上,测试二进制文件在本地机器上编译,但在另一台远程服务器上运行为什么您认为coverprofile不同从一台机器到另一台机器的nt?只是因为测试程序甚至不能在编译机器上运行,有太多的微服务依赖于运行测试,而编译机器以前不能提供这种服务,但不能工作,并且发生了一个安装结果:Issue SIGINT不能停止程序。我跟踪了MKrtE之后执行的每一行ixt(0)->mkrtExitWait.Done()->mkrtExitWait.Wait()->main.go返回,但程序仍在运行,我想这与测试birnary有关,如果我运行main.go,SIGINT可以停止程序os.Exit(0)或panic()可以停止测试程序,但mkrtexit(0)我猜你的MKrtEixt
func有一个bug!我一直在使用这个方法,除了我们必须停止http服务器来代替调用os.Exit()我可能知道main()return无法停止测试程序的原因,当生成测试二进制文件时,可能会添加另一个main()函数来执行TestSystem()函数,TestSystem()然后执行我定义的main()函数,这意味着我们看到的main()函数不是在主协程中运行的真正的main()函数,因此当它返回时,主协程没有任何效果,整个程序仍然运行,仅通过执行os.Exit(0),我们可以停止程序吗?在这种情况下,您认为给出的答案正确吗?我建议编辑答案/问题以添加您的警告。可能是其他人:-)我有相同的问题。您能详细说明您的解决方案吗?我有相同的问题。我正在从TestMain()中的_test.go文件调用main().我已经确保这是我回购协议中的唯一测试。但仍然没有报告。你能详细说明你的解决方案吗?看我的答案,我根据这个提示详细说明了
func TestMain(t *testing.T) {
run := false
for _, arg := range os.Args {
switch {
case arg == "systemTest":
run = true
}
}
if run {
main()
fmt.Println("returned from main")
}
}