I recently started playing with go build -cover -o
to collect the code coverage for integration test in Go 1.20. I used the textfmt
to get the coverage, but looking at the text file, it has a local path for the file that I built the executable for, and a module url for the utility function which resides in the same project. Below is an example:
./main/program.go
package main
import "example.com/m/util"
func main() {
util.PrintFromUtil()
}
./util/util.go
package util
import "fmt"
func PrintFromUtil() {
fmt.Println("This is from package util")
}
./go.mod
module example.com/m
go 1.20
This are the commands I used for getting the coverage profile:
$ go build -cover -o ./main/program ./main/program.go
$ GOCOVERDIR=coverage ./main/program
This is from package util
$ go tool covdata textfmt -i=coverage -o profile.txt
$ cat profile.txt
mode: set
/MYLOCALPATH/main/program1.go:5.13,7.2 1 1
example.com/m/util/util.go:5.22,7.2 1 1
The issue seems to be the import. One easy fix is just to clean up the profile.txt manually by replacing the local path with the project url or vice versa. However, is there any cleaner way to do this? Since it is meant for integration tests, I can imagine there should be plenty of imports in the tests. Any help is appreciated.
Digging deeper:
The issue is that you specify a file when building the binary, not a package. It goes away when you change
go build -cover -o ./main/program ./main/program.go
to
go build -cover -o ./main/program ./main
On the other hand, main
seems to be a problematic path name.
May I suggest that you restructure your source for example to cmd/program
mkdir cmd
mv main cmd/program
and then use
go build -cover ./cmd/program
./program
instead?
Old answer:
It seems you are not using Go modules (no go.mod
file) and working outside the $GOPATH
, so this is the import path for your main
function.
How about putting your code inside the example.com/m
module? You can also make a new module and combine multiple modules inside a workspace if you want to further organize your source - or work inside the GOPATH
. Most people choose the first option, since it's the most simple one, but your use case might be different.