go语言的测试覆盖(2)

今天讲一下go语言的test coverage是如何实现的。

上篇讲到了go语言1.2之前对于测试覆盖的支持,使用了比较“传统”的做法,也就是对于二进制文件的analysis和instrument。

从go v1.2开始,新的测试覆盖工具使用了完全不同的方法。思路非常简单:在编译之前重写源文件,在源文件中加入一些instrument,然后编译和执行被修改的源文件,得到覆盖的统计信息。重写源文件其实不难,得益于go强大的命令行工具 - 它负责从源文件编译,到执行测试,直到程序的执行全盘搞定 - 所以在这个全过程的工具中“重写”代码不在话下。

一起看看下面的简单例子:

package size

func Size(a int) string {
    switch {
    case a < 0:
        return "negative"
    case a == 0:
        return "zero"
    case a < 10:
        return "small"
    case a < 100:
        return "big"
    case a < 1000:
        return "huge"
    }
    return "enormous"
}

以及单元测试代码:

package size

import "testing"

type Test struct {
    in  int
    out string
}

var tests = []Test{
    {-1, "negative"},
    {5, "small"},
}

func TestSize(t *testing.T) {
    for i, test := range tests {
        size := Size(test.in)
        if size != test.out {
            t.Errorf("#%d: Size(%d)=%s; want %s", i, test.in, size, test.out)
        }
    }
}

运行go test命令的时候加上-cover参数就可以得到覆盖率的统计数据。

% go test -cover
PASS
coverage: 42.9% of statements
ok  	size	0.026s
%

接下来我们看看这个统计数据是怎么计算得出的。当带上-cover参数之后,go test会运行一个独立的程序,名字就叫cover,它会在编译之前改写源代码。

改写之后的代码差不多长这个样子:

func Size(a int) string {
    GoCover.Count[0] = 1
    switch {
    case a < 0:
        GoCover.Count[2] = 1
        return "negative"
    case a == 0:
        GoCover.Count[3] = 1
        return "zero"
    case a < 10:
        GoCover.Count[4] = 1
        return "small"
    case a < 100:
        GoCover.Count[5] = 1
        return "big"
    case a < 1000:
        GoCover.Count[6] = 1
        return "huge"
    }
    GoCover.Count[1] = 1
    return "enormous"
}

注意代码中新加入的行,它们分布在代码的每个分支上,当对应的分支被执行到的时候它们就会做对应的记录。它们看起来像是计数器,每个计数器都会记录对应在代码中的原始位置。这些重要的对应信息都是由"cover"程序生成的。当测试程序运行完毕后,计数器会被收集起来,计算覆盖的结果。虽然新加入的那些行看着代价挺高,其实不然,因为都是简单的赋值操作,它们被编译成"MOV"指令,所以它们的运行时开销也不大,通常的影响是大约3%。这对于日常的开发不会造成负面影响。

查看覆盖率结果

go test命令能够将覆盖率结果输出到文件中,以便我们查看是哪些代码行没有被测试覆盖到。

% go test -coverprofile=coverage.out
PASS
coverage: 42.9% of statements
ok  	size	0.030s
%

参数 -coverprofile会自动设置 -cover参数,启用覆盖率分析。我们可以用如下命令查看结果文件:

% go tool cover -func=coverage.out
size.go:	Size          42.9%
total:      (statements)  42.9%
%

当然,一种更加让人喜闻乐见的格式是HTML。

$ go tool cover -html=coverage.out

执行这个命令会打开一个浏览器,用图形化的方式显示覆盖的细节。

如果觉得这篇文章对你有用,点击关注,或者留言讨论,一起在学习的大道上超越昨天的自己。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bruce Jia(上海)

熬夜码字换酒钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值