获取 Golang 的覆盖率信息的程序化方法

huangapple go评论76阅读模式
英文:

Get golang coverage programmatically

问题

go -cover或-coverprofile在运行go测试时非常好用,可以以HTML或纯文本的形式展示。但是是否有API可以以编程方式访问它或处理该文件呢?

英文:

The go -cover or -coverprofile is great when running go tests and can show nicely in html or plain text. But is there an api to access it programmatically or process the file?

答案1

得分: 4

你可以尝试使用axw/gocov,它具有以下功能:

你可以看到像GoCov GUI这样的工具在convert_statements(s []*gocov.Statement, offset int)中使用gocov.Statement来构建一个小型的GUI:

获取 Golang 的覆盖率信息的程序化方法

英文:

You can try axw/gocov, which:

You can see a tool like GoCov GUI uses gocov.Statement in convert_statements(s []*gocov.Statement, offset int) in order to build a small GUI:

获取 Golang 的覆盖率信息的程序化方法

答案2

得分: 1

假设我们想要从某个地方动态获取项目,并将其存储在当前文件夹下的"_repos/src"文件夹中,然后获取测试覆盖率百分比(作为float64)。输入将是项目的典型"go get"格式。我们需要执行"go test -cover"命令,并设置正确的GOPATH变量,解析输出,并提取测试覆盖率的实际百分比。使用当前的Go 1.9测试工具,下面的代码可以实现这一目标。

// ParseFloatPercent将带有数字%的字符串转换为浮点数。
func ParseFloatPercent(s string, bitSize int) (f float64, err error) {
    i := strings.Index(s, "%")
    if i < 0 {
        return 0, fmt.Errorf("ParseFloatPercent: percentage sign not found")
    }
    f, err = strconv.ParseFloat(s[:i], bitSize)
    if err != nil {
        return 0, err
    }
    return f / 100, nil
}

// GetTestCoverage返回测试代码覆盖率作为浮点数
// 我们假设project是一个字符串
// 以标准的"go get"形式,例如:
//     "github.com/apache/kafka"
// 并且,你已经将仓库克隆到当前文件夹下的"_repos/src"中。
//
func GetTestCoverage(project string) (float64, error) {
    cmdArgs := append([]string{"test", "-cover"}, project)
    cmd := exec.Command("go", cmdArgs...)
    // 获取我们主可执行文件的绝对路径
    dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    if err != nil {
        log.Println(err)
        return 0, err
    }
    // 设置测试的GOPATH
    cmd.Env = os.Environ()
    cmd.Env = append(cmd.Env, "GOPATH="+dir+"/_repos/")

    var out []byte
    cmd.Stdin = nil
    out, err = cmd.Output()

    if err != nil {
        fmt.Println(err.Error())
        return 0, err
    }

    r := bufio.NewReader(bytes.NewReader(out))
    // 运行"go test -cover"后的第一行应该是以下形式
    // ok  	<project>	6.554s	coverage: 64.9% of statements
    // 使用制表符和空格进行分割
    line, _, err := r.ReadLine()

    if err != nil {
        fmt.Println(err.Error())
        return 0, err
    }

    parts := strings.Split(string(line), " ")
    if len(parts) < 6 {
        return 0, errors.New("go test -cover do not report coverage correctly")
    }
    if parts[0] != "ok" {
        return 0, errors.New("tests do not pass")
    }
    f, err := ParseFloatPercent(parts[3], 64)
    if err != nil {
        // 百分比解析问题
        return 0, err
    }

    return f, nil
}

以上代码可以实现从git仓库中获取项目,并计算测试覆盖率的百分比。

英文:

Let us assume that we want to obtain test coverage percentage (as float64) on a project that we dynamically fetch from a git repo from somewhere, and store in the current folder under "_repos/src". The input would be the project in a typical "go get" format. We need to execute "go test -cover", with the properly GOPATH variable set, parse the output, and extract the actual percentage of the test coverage. With the current Go 1.9 testing tool, the code below achieves that.

// ParseFloatPercent turns string with number% into float.
func ParseFloatPercent(s string, bitSize int) (f float64, err error) {
i := strings.Index(s, &quot;%&quot;)
if i &lt; 0 {
return 0, fmt.Errorf(&quot;ParseFloatPercent: percentage sign not found&quot;)
}
f, err = strconv.ParseFloat(s[:i], bitSize)
if err != nil {
return 0, err
}
return f / 100, nil
}
// GetTestCoverage returns the tests code coverage as float
// we are assuming that project is a string
// in a standard &quot;Go get&quot; form, for example:
//     &quot;github.com/apache/kafka&quot;
// and, that you have cloned the repo into &quot;_repos/src&quot;
// of the current folder where your executable is running.
//
func GetTestCoverage(project string) (float64, error) {
cmdArgs := append([]string{&quot;test&quot;, &quot;-cover&quot;}, project)
cmd := exec.Command(&quot;go&quot;, cmdArgs...)
// get the file absolute path of our main executable
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
log.Println(err)
return 0, err
}
// set the GOPATH for tests to work
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, &quot;GOPATH=&quot;+dir+&quot;/_repos/&quot;)
var out []byte
cmd.Stdin = nil
out, err = cmd.Output()
if err != nil {
fmt.Println(err.Error())
return 0, err
}
r := bufio.NewReader(bytes.NewReader(out))
// first line from running &quot;go test -cover&quot; should be in a form
// ok  	&lt;project&gt;	6.554s	coverage: 64.9% of statements
// split with /t and &lt;space&gt; characters
line, _, err := r.ReadLine()
if err != nil {
fmt.Println(err.Error())
return 0, err
}
parts := strings.Split(string(line), &quot; &quot;)
if len(parts) &lt; 6 {
return 0, errors.New(&quot;go test -cover do not report coverage correctly&quot;)
}
if parts[0] != &quot;ok&quot; {
return 0, errors.New(&quot;tests do not pass&quot;)
}
f, err := ParseFloatPercent(parts[3], 64)
if err != nil {
// the percentage parsing problem
return 0, err
}
return f, nil
}

huangapple
  • 本文由 发表于 2014年7月9日 11:13:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/24644823.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定