在IntelliTest实战直通车(上集)中,我们对IntelliTest有了一个初步了解,接下来进一步了解IntelliTest的其他特性。
一个更真实的栗子
这部分请允许我借花献佛,因为官方的栗子足够清晰(其实就是懒(/▽\)),如果你实在习惯阅读中文,这里有一个翻译的版本。
Pex
PexFramework是整个IntelliTest的核心,通过PexFramework可以配置IntelliTest的探测规则,用例的生成行为等。
配置探测边界
IntelliTest探测过程中伴随这约束求解器的工作,它会及时的计算出下一组输入参数,微软已开源了约束求解器,有志之士可以研究源码。虽然官方文章中说,当覆盖率达到100%后会停止探测,然而实际情况却不是这样。恰恰相反,IntelliTest的探测往往是无止尽的,特别在函数内部有遍历,而遍历的次数又依赖参数时。为了优化探测的性能消耗,Pex提供了一套配置API,开发者可以选择从不同的维度去限制IntelliTest探测的性能消耗。现在需要为如下代码生成用例:
public static int Sum(int count)
{
int sum = 0;
for (int i = 1; i < count + 1; i++)
{
sum += i;
}
return sum;
}
运行IntelliTest后会发现有103次run,异常窗口中显示“达到值为 100 的探索边界 max runs without new tests”,意思是运行了100次也没有新的用例生成,IntelliTest自动停止,100是默认值。假设我们想修改为20,只需要在PUT方法上增加特性设置:
[PexMethod(MaxRunsWithoutNewTests = 20)]
public int Sum(int count)
{
int result = CalculatorHelper.Sum(count);
return result;
}
对于探测的终止边界,可以配置在方法级别,也可以配置在类级别和程序集级别。Pex提供了丰富的配置以优化探测性能,还包括以下特性:
-
MaxBranches:可能沿单个执行路径使用的最大分支数
-
MaxCalls:可能在单个执行路径期间执行的最大调用数
-
MaxConditions: 可能在单个执行路径期间检查的最大输入条件数
-
MaxConstraintSolverMemory: 约束求解器可能用于发现输入的大小 (MB)
-
...
静态辅助API
静态辅助API旨在辅助PUT约束用例生成行为,比如 一个更真实的栗子 中的PexAssume。除此之外还有PexChoose,它可以配置生成用例时使用的参数的范围。看起来好像和PexAssume类似,都是限制用例生成行为,但是它们还是有区别的,PexAssume会按照通用流程生成所有输入参数,只有符合PexAssume要求的才会生成用例,而PexChoose则直接在限定的范围内生成输入参数。
警告
通过IntelliTest,可以为我们自动生成用例,但是仍然有一些情况是IntelliTest无法处理的,此时它会通过警告的方式告诉我们,大致有以下一些情况:
-
超过了配置的探测边界,就像 配置探测边界 中一样
-
IntelliTest无法决定使用接口的哪个实现
-
IntelliTest无法探测某些方法
-
IntelliTest无法构造某些实例
-
...
IntelliTest的限制
IntelliTest期望可以自动生成测试用例,然而这项工作并不容易,存在一些情况是现在版本的IntelliTest无法处理的:
- 语言:原则上,测试引擎可以分析所有.NET语言编写的程序,但是,测试代码仅以C#生成
- 非确定性:IntelliTest假定受测试代码时确定的,如果不是,则不会走不确定性代码分支(比如用了随机数)
- 并发:测试引擎不处理多线程
- 本地代码:无法探测本地代码
- 不支持 .NET Standard 的类库
- 基于Block的覆盖,所以在某些情况下,IntelliTest可能无法保证程序得到完整的测试,比如下面的代码:
IntelliTest生成的用例中将不会包含 fileNameLower.EndsWith("pptx") 为 true 的输入,因为它为 false 时也算被覆盖过了。/// <summary> /// 判断文件名是否为PPT文件 /// </summary> /// <param name="fileName"></param> /// <returns></returns> public static bool IsPptFile(string fileName) { var fileNameLower = fileName.ToLower(); if (fileNameLower.EndsWith("ppt") || fileNameLower.EndsWith("pptx")) { return true; } return false; }
总结
通过上下两集对IntelliTest的介绍,可以看出IntelliTest通过自动生成用例的方式,可以Cover到一些开发者容易忽略的情况。然而,它始终是机器,它只认识一条条的语句,它可以是一个很好的辅助工具,但它不能完全替代开发者写单元测试。这两篇文档只是对IntelliTest的基本理念和使用做了介绍,希望了解更多细节可参考:
2017-10-30 21:28:22
网友评论