无法生成Go Coverage文件

时间:2018-07-23 10:05:37

标签: go test-coverage

我尝试在本文中运行sytemTest: https://www.elastic.co/blog/code-coverage-for-your-golang-system-tests

所以请遵循提示 首先,我创建一个名为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

因为该程序将侦听并等待客户的请求,所以除非我退出manunal,否则它不会退出,这意味着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()
}

我尝试了一些方法来生成coverage文件,如下所示,但它不起作用:

  1. 发送客户端请求以告诉测试服务器在程序运行时执行os.Exit(0)

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

  3. 杀死强制退出程序的过程

出什么问题了?

如何生成覆盖文件?

4 个答案:

答案 0 :(得分:1)

为我解决的问题(并在@darkwing的答案中提到)是标志顺序。

当我首先放置-test.coverprofile=coverage.cov时,它可以工作,并创建了coverage.cov文件。

注意:我必须在标志名称和值之间添加=符号。

我也不需要在其他go例程中运行它。

答案 1 :(得分:0)

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

这意味着您需要修改主程序才能在某些中断时退出。 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)
        }() 

所以您的测试步骤应该是

  1. 启动被测系统
  2. 运行外部测试
  3. 测试完成后,将SIGINT分发到被测系统
  4. 收集报道文件

答案 2 :(得分:0)

我弄清楚了为什么不能生成Coverprofile的原因..

主要协程由测试二进制文件启动,它将等待util完成所有测试任务,并最终覆盖coverage文件。 主功能测试是一项任务,因此如果主功能执行os.Exit(0),则不会生成coverage文件。 在我的测试程序中,当主要功能测试任务结束时,还有其他一些测试任务要执行,其中一个被I / O事件阻止而没有超时,因此它与主要功能测试任务无关。

答案 3 :(得分:0)

OP提示了一个答案,但并未给出答案。关键在于,要编写coverage配置文件,程序需要将执行返回到TestMain,而不能仅调用os.Exit(0)

因此,真正需要做的只是在主goroutine中使用return处理一点代码。下面是示例代码,它使用以下代码编译测试二进制文件后运行:

go test -c -covermode=count -cover -coverpkg ./...

然后运行如下(引号在Windows的Powershell中是必需的,但在cmd中不是必需的):

testmain.test.exe "-test.coverprofile" coverage.cov systemTest

我发现由于某种原因,仅当我的自定义标记systemTest紧随-test.coverprofile coverage.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
}

main_test.go:

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")
    }
}

灵感:https://www.cyphar.com/blog/post/20170412-golang-integration-coveragehttps://www.elastic.co/blog/code-coverage-for-your-golang-system-tests