无法生成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() } } 当执行此单元测试时,将执行整个主功能 然后我构建

我在本文中尝试运行了一个系统测试:

因此,请遵循提示 首先,我创建一个名为main_test.go的系统测试文件,如下所示:

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()
}
我尝试了以下几种方法来生成覆盖率文件,但不起作用:

  • 发送客户端请求,通知测试服务器在程序运行时执行os.Exit(0)

  • 发送一个客户端请求,告诉测试服务器在程序运行时执行panic()

  • 终止进程以强制退出程序

  • 有什么问题吗


    如何生成覆盖率文件?

    系统测试通常在您的测试上运行一些外部测试时使用

    这意味着您需要修改主程序以退出某些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")
        }
    }