IntelliTest实战直通车(下集)

  在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可能无法保证程序得到完整的测试,比如下面的代码:
        /// <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的基本理念和使用做了介绍,希望了解更多细节可参考:

date: 2017-10-30 21:28:22

posted @ 2018-02-05 22:56  .NET学徒  阅读(294)  评论(0编辑  收藏  举报