IntelliTest实战直通车(下集)

  在IntelliTest实战直通车(上集)中,我们对IntelliTest有了一个初步了解,接下来进一步了解IntelliTest的其他特性。

一个更真实的栗子

  这部分请允许我借花献佛,因为官方的栗子足够清晰(其实就是懒(/▽\)),如果你实在习惯阅读中文,这里有一个翻译的版本

Pex

  PexFramework是整个IntelliTest的核心,通过PexFramework可以配置IntelliTest的探测规则,用例的生成行为等。

配置探测边界

  IntelliTest探测过程中伴随这约束求解器的工作,它会及时的计算出下一组输入参数,微软已开源了约束求解器,有志之士可以研究源码。虽然官方文章中说,当覆盖率达到100%后会停止探测,然而实际情况却不是这样。恰恰相反,IntelliTest的探测往往是无止尽的,特别在函数内部有遍历,而遍历的次数又依赖参数时。为了优化探测的性能消耗,Pex提供了一套配置API,开发者可以选择从不同的维度去限制IntelliTest探测的性能消耗。现在需要为如下代码生成用例:

1
2
3
4
5
6
7
8
9
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方法上增加特性设置:

1
2
3
4
5
6
[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可能无法保证程序得到完整的测试,比如下面的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /// <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生成的用例中将不会包含 fileNameLower.EndsWith(“pptx”) 为 true 的输入,因为它为 false 时也算被覆盖过了。

总结

  通过上下两集对IntelliTest的介绍,可以看出IntelliTest通过自动生成用例的方式,可以Cover到一些开发者容易忽略的情况。然而,它始终是机器,它只认识一条条的语句,它可以是一个很好的辅助工具,但它不能完全替代开发者写单元测试。这两篇文档只是对IntelliTest的基本理念和使用做了介绍,希望了解更多细节可参考:

-------------本文结束 感谢您的阅读-------------

本文标题:IntelliTest实战直通车(下集)

文章作者:nero

发布时间:2017年10月30日 - 21:10

最后更新:2017年10月31日 - 16:10

原始链接:http://erdao123.oschina.io/nero/2017/10/30/UnitTest/IntelliTest/IntelliTest实战直通车-下集/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。