使用代码覆盖范围来调试大型GO应用程序
#测试 #go

代码覆盖范围通常用作代码质量指标。

一个人可以运行

go test -coverpkg ./... -coverprofile test.cov ./...

并接收一个test.cov文件,其中包含有关执行过程中代码特定部分的频率的信息。

这是保持测试相关的好工具。

但是,代码覆盖范围也可以帮助您调试大型代码库!

想象一个看似无辜的代码变化导致测试破裂的情况。如果执行中涉及大量代码,则达到根本原因可能是不平凡的。

在较小的情况下,您可以通过调试器浏览所有陈述并比较状态和条件,但是当您有成千上万的陈述时,这种方法并不可行。

代码覆盖范围可以帮助您缩小调试的范围。

这是食谱。先决条件是您有一个通过原始代码通过的测试,并且在新的代码中失败。

收集覆盖范围

收集失败和通过的覆盖范围。

重要的是要在所有包装上收集覆盖范围以具有全面的图片。您可以使用./...my-module/...github.com/foo/my-module/... for -coverpkg

应用更改并运行测试。

go test -cover -coverpkg ./... -coverprofile new.cover -run ^Test_Foo$ ./path/to/tested/package

然后恢复更改并再次收集覆盖范围。

go test -cover -coverpkg ./... -coverprofile orig.cover -run ^Test_Foo$ ./path/to/tested/package

之后,您最终将有两个文件:orig.covernew.cover

它们可能很大,但希望不会很大。

覆盖范围的文件可能看起来像这样。

mode: set
github.com/swaggest/jsonschema-go/camelcase.go:14.31,21.22 6 1
github.com/swaggest/jsonschema-go/camelcase.go:21.22,22.27 1 1
github.com/swaggest/jsonschema-go/camelcase.go:22.27,24.4 1 1
github.com/swaggest/jsonschema-go/camelcase.go:26.3,26.27 1 1
github.com/swaggest/jsonschema-go/camelcase.go:26.27,28.4 1 1
github.com/swaggest/jsonschema-go/camelcase.go:30.3,30.27 1 1
.....

第一行说使用了哪种覆盖范围收集方式。

所有其他行描述了代码的跨度(file:start_line.start_col,end_line.end_col),其中该跨度为语句,并且执行了许多语句。

创建覆盖范围差异

按字母顺序排列的覆盖范围文件,因此它们对diff友好。

diff orig.cover new.cover > diff.cover

生成的文件看起来可能与此相似。

305c305
< github.com/swaggest/jsonschema-go/helper.go:75.46,78.16 2 1
---
> github.com/swaggest/jsonschema-go/helper.go:75.46,78.16 2 0
307c307
< github.com/swaggest/jsonschema-go/helper.go:82.2,84.46 2 1
---
> github.com/swaggest/jsonschema-go/helper.go:82.2,84.46 2 0
309c309
< github.com/swaggest/jsonschema-go/helper.go:88.2,88.15 1 1

您已经可以发现,在执行语句的数量中,这里的行大部分是不同的。这是我们的线索,即代码中的那些地方是最佳候选人,可以通过调试器更深入地看待。

让我们更方便地跟随和检查。

覆盖范围报告

<开头的行表示原始代码,以>开头的行是关于新代码的。

我们可以从差异

构建过滤的覆盖范围报告

为此,我们需要还原mode: set并从行中删除"< ""> "

echo "mode: set" > orig_flt.cover && grep "< " diff.cover | sed 's/< //' >> orig_flt.cover

echo "mode: set" > new_flt.cover && grep "> " diff.cover | sed 's/> //' >> new_flt.cover

现在,有两个覆盖范围文件仅包含两个运行之间的差异。

我们可以方便地使用标准go tool cover进行检查。

go tool cover -html=orig_flt.cover -o orig_flt.html
go tool cover -html=new_flt.cover -o new_flt.html

Coverage diff screenshot

您可以查看代码的执行方式不同,这可能会导致一个可能是根本原因的想法,或者至少可以在设置调试器中断点的情况下提示。

我希望您喜欢阅读本文,就像我喜欢使用这种方法挖掘Huuuuge代码基础一样。 :)