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?
You can try axw/gocov
, which:
-coverprofile
argumentgocov/convert.go
)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:
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, "%")
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 returns the tests code coverage as float
// we are assuming that project is a string
// in a standard "Go get" form, for example:
// "github.com/apache/kafka"
// and, that you have cloned the repo into "_repos/src"
// of the current folder where your executable is running.
//
func GetTestCoverage(project string) (float64, error) {
cmdArgs := append([]string{"test", "-cover"}, project)
cmd := exec.Command("go", 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, "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))
// first line from running "go test -cover" should be in a form
// ok <project> 6.554s coverage: 64.9% of statements
// split with /t and <space> characters
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 {
// the percentage parsing problem
return 0, err
}
return f, nil
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With