在UNITY我们是如何使用代码覆盖的?
原文地址:http://blogs.unity3d.com/2014/02/27/how-do-we-use-code-coverage-for-unity/
原文作者未做版权声明,视为共享知识产权进入公共领域,自动获得授权
我们之前已经写过关于运营时测试、性能测试和Unity测试工具。在这篇文章里面,我将讲述我们是如何使用代码覆盖的。
首先,代码覆盖是一个需要很多支持的事情,使用起来要非常小心。如果把它理解成为衡量质量的测试套件是不正确的。你可以很容易写出一个没有一个断言的测试套件,但是产生了100%的覆盖。代码覆盖率让我们彻底了解我们的测试套件。结合其他指标,将会是非常有用的。
我们第一个目标是看看我们现在的测试组件有多少C++代码。我们评价了很多不同的C++代码覆盖工具,最后选择了BullseyeCoverage。原因是:
l 我们喜欢它测量的内容
l 很容易集成到我们的构建系统
l 广泛的平台支持
l 授权和定价符合我们的需求
l 良好的支持
我们测量的内容
语句覆盖
最广为人知的覆盖指标可能是语句覆盖了。我们没有使用这个指标,但是这里仍然有一个小例子:
int* p = NULL;
if (condition) {
p =&variable;
}
*p = 123;
如果条件为真,我们有100%的语句覆盖率这意味着每个语句都被覆盖到了。但是100%的语句覆盖率真的足够测试代码了么?很明显我们需要至少两个测试用例,一个用于条件为真的时候,一个用于条件为假的时候。
决策覆盖
只要上面例子中的条件的真和假都考虑到了,就是100%的决策覆盖率。布尔表达式比单独一个变量更加复杂。决策覆盖不考虑这一点,所以需要条件覆盖。
条件覆盖
考虑下面的布尔表达式:
If (c1 && c2 && c3) {
statement1;
} else {
statement2;
}
指标显示了100%的条件覆盖率,c1,c2,c3一共有6种组合。c1 ,c2, c3是 条件,而(c1 && c2 && c3)则是决策。
但是重要的是,100%的条件并不意味着100%的决策覆盖,如下面这个例子:
If (c1 && c2) {
}
在这种情况,设置c1=true,c2=false 或者c1=false, c2=true可以满足条件覆盖,但是不是决策覆盖。
条件/决策覆盖
BullseyeCoverage对条件和决策覆盖有一个综合(在后面的章节中简写为C/D覆盖)。
If (c1 && c2 && c2) {
statement1;
} else {
statement2;
}
对一段有100%的覆盖率意味着:
l 每一个条件c1, c2, c3的真和假都覆盖到了
l 决策(c1 && c2&& c3)的真和假评估了
更加详细的解释请看这里: 代码覆盖分析
函数覆盖
我们还测试了函数覆盖,这个会告诉我们每个函数是否被覆盖到。
我们如何使用
追踪随时间变化的覆盖率
C++代码现在有了C/D覆盖率和函数覆盖率,我们会追踪它们是如何随着啥时间变化的,下图是一个例子:
X轴是日期,Y轴是百分比
我们会注意到覆盖率的高低起伏。有时候会下降的原因是:
l 有没有测试的新代码加进来了
l 测试组件发生了变化(测试例子移到了其他组件,或者被删除)
确定丢失的覆盖率
当我们有了这个数据以后,很容易看到Unity代码那些部分被测试覆盖:
这份报告指出每个部分都有不错的覆盖率。可以为每个套件输出报告,也可以输出总体报告,我们选择的是总体报告。
优化测试组件的同时又不丢失覆盖率:
我们有各种测试组件:
l 原生
l 集成
l 图形
l 运行时
l 其他
我们下一步的目标是建立一个快速最小的测试集,同时每个测试集保留高覆盖绿。本地测试将是微不足道的,但是其他测试组件我们要处理的更聪明一点,代码覆盖率将是非常重要的,因为它能让我们知道代码是如何执行的。
把慢的集成测试换成快速本地测试
当把选择的高阶测试转换成本地C++单元测试,我们可以通过覆盖绿来保证我们在转换前后测试了同一段代码。
提高测试和代码评审
开发和测试人员可以使用代码覆盖绿来作为一个参数来评审代码和测试。它可能提供一些意想不到的结果。在做手工测试的时候,我们也可以看下代码覆盖绿来准确的知道哪些部分的代码已经被测试过了。
下一步
继续前进,对于我们一个有趣的挑战是在测试和代码测试执行之间建立一个对应关系。这将给我们一些激动人心的可能性:
l 找到测试相同代码的测试。这样的测试需要重新审查以及决定是否要消除。
l 增量覆盖 最近新加了多少代码覆盖
l 分析变化以及只运行和这些变化有关的测试
l 为托管代码追踪覆盖率
我们相信有一个坚定的代码覆盖方案会给我们一些很有意思的可能性。我们将分享前进过程中我们的发现。