Golang中Cover命令报告代码覆盖率不准确的问题

Golang中Cover命令报告代码覆盖率不准确的问题 这是我第一次尝试为Go应用程序进行代码覆盖率实验。

我正在尝试使用 -cover 标志来测试代码覆盖率,但针对的是REST端点。 我参考了这篇文章:https://go.dev/doc/build-cover 上面的例子在我的机器上运行良好——然而,当我尝试将其扩展到一个简单的REST API时,它似乎没有显示0%的代码覆盖率。

这是我正在尝试处理的一个更小版本的原型。 即使我看到端点被访问、数据被检索,我看到的代码覆盖率仍然是0%。

main.go

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

type Item struct {
	ID    string `json:"id"`
	Name  string `json:"name"`
	Price int    `json:"price"`
}

var inventory []Item

func main() {
	// 初始化库存
	inventory = []Item{
		{ID: "1", Name: "Keyboard", Price: 50},
		{ID: "2", Name: "Mouse", Price: 20},
	}

	http.HandleFunc("/items", getItems)
	http.HandleFunc("/item/", getItemByID)

	log.Print("Starting server at port 8080")

	log.Fatal(http.ListenAndServe(":8080", nil))

}

func getItems(w http.ResponseWriter, r *http.Request) {
	// 记录方法
	log.Print("INVOKED > getItems ; URL : ", r.URL)

	w.Header().Set("Content-Type", "application/json")
	if err := json.NewEncoder(w).Encode(inventory); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func getItemByID(w http.ResponseWriter, r *http.Request) {
	// 记录方法
	log.Print("INVOKED > getItemByID ; URL : ", r.URL)

	id := r.URL.Path[len("/item/"):]
	for _, item := range inventory {
		if item.ID == id {
			w.Header().Set("Content-Type", "application/json")
			if err := json.NewEncoder(w).Encode(item); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			return
		}
	}
	http.NotFound(w, r)
}

以下是我如何触发REST应用程序

curl http://localhost:8080/items
curl http://localhost:8080/item/1
curl http://localhost:8080/item/2

以下是我如何构建二进制文件

go build -cover -o myapp.exe main.go
GOCOVERDIR=coverData ./myapp.exe

我看到覆盖率文件在cover文件夹中生成——我注意到这里它没有在我的cover文件夹中生成covcounters文件

$ ls coverData
covmeta.a9e2dc969ed2da98e736682fc77dd35f

以下是我如何生成代码覆盖率和报告

$ go tool covdata textfmt -i=coverData -o cov_func.txt
$ go tool cover -func=cov_func.txt
\my-go-rest-get\main.go:17:    main        0.0%
\my-go-rest-get\main.go:33:    getItems    0.0%
\my-go-rest-get\main.go:44:    getItemByID 0.0%
total:                                                                          (statements)
0.0%

背景:

我的最终目标是将此代码覆盖率迁移到一个更大的微服务生态系统,其中有多个Go服务在运行,并在这些Go服务上运行我们的REST集成测试套件。我们的代码库中已经有超过90%的丰富单元测试覆盖率。

我们的计划是更好地了解REST集成测试套件中需要改进的地方。

注意:这是我的第一篇帖子,不太确定这个问题是否已经被讨论过。


更多关于Golang中Cover命令报告代码覆盖率不准确的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中Cover命令报告代码覆盖率不准确的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题在于你直接运行了编译后的二进制文件,而没有通过 go test 来执行测试。-cover 标志在 go build 中主要用于生成可收集覆盖率数据的二进制文件,但实际的覆盖率收集需要结合测试执行。以下是正确的做法:

首先,为你的 HTTP 处理函数编写测试文件 main_test.go

package main

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestGetItems(t *testing.T) {
	req := httptest.NewRequest("GET", "/items", nil)
	w := httptest.NewRecorder()
	getItems(w, req)

	res := w.Result()
	if res.StatusCode != http.StatusOK {
		t.Errorf("expected status OK, got %v", res.StatusCode)
	}
}

func TestGetItemByID(t *testing.T) {
	tests := []struct {
		path       string
		statusCode int
	}{
		{"/item/1", http.StatusOK},
		{"/item/2", http.StatusOK},
		{"/item/3", http.StatusNotFound},
	}

	for _, tt := range tests {
		req := httptest.NewRequest("GET", tt.path, nil)
		w := httptest.NewRecorder()
		getItemByID(w, req)

		res := w.Result()
		if res.StatusCode != tt.statusCode {
			t.Errorf("for path %s, expected status %v, got %v", tt.path, tt.statusCode, res.StatusCode)
		}
	}
}

然后使用以下命令运行测试并收集覆盖率数据:

# 运行测试并生成覆盖率文件
go test -cover -coverprofile=coverage.out

# 查看覆盖率报告
go tool cover -func=coverage.out

# 生成HTML格式的覆盖率报告
go tool cover -html=coverage.out -o coverage.html

如果你需要为集成测试收集覆盖率,可以使用 -coverpkg 标志指定要覆盖的包:

go test -cover -coverpkg=./... -coverprofile=coverage.out ./...

对于微服务生态系统的集成测试覆盖率收集,建议使用 go test 配合适当的测试框架(如 testify)来模拟 HTTP 请求,而不是直接运行二进制文件。这样可以确保覆盖率数据准确反映测试执行过程中实际运行的代码路径。

回到顶部