
11.6 IntelliTest
在单元测试方面,Visual Studio 2015引入的一个新功能是IntelliTest。它是Pex项目的产物,多年来,Pex项目一直活跃在微软研究院里。虽然IntelliTest可以用在许多不同的情况下,但其优点是在单元测试覆盖率中填补“漏洞”——例如旧代码完全没有单元测试时的漏洞,或者单元测试已经编写好,但没有覆盖被测试类的边界情况时的漏洞。
为提供这个功能,IntelliTest会分析用户指定的、应测试的方法。对于每一个方法,应通过代码确定可以采取的不同路径。然后设置检查路径所需的任何参数的精确值,为每个路径生成单元测试。我们的目标是创建一组单元测试,尽可能完全涵盖代码。
要创建一组IntelliTest,首先应右击要测试的类,从上下文菜单中选择Run IntelliTest。这会检查类中的代码,生成相应的单元测试,运行它们。为了解生成的测试,可以考虑以下方法,该方法添加到前面章节描述的Subscription类中。
VB
Private subscribers = New List(Of Person) Public Sub AddSubscriber(ByVal person As Person, paidToDate As DateTime?) If person.Country <> "US" And person.Country <> "CAN" Then Return End If Dim existingSubscriber As Person = subscribers.Where( _ Function(p)p == person).FirstOrDefault() If existingSubscriber Is Nothing Then Subscribers.Add(person) End If End Sub
C#
private List<Person> subscribers = new List<Person>(); public void AddSubscriber(Person person, DateTime? paidToDate) { if (person.Country != "US" && person.Country != "CAN") return; var existingSubscriber = subscribers.Where( p => p == person).FirstOrDefault(); if (existingSubscriber == null) subscribers.Add(person); }
输出如图11-12所示。

图11-12
在图11-12中,IntelliTest过程生成了两个单元测试。在target旁边的列中,可以看到所提供的值作为每次运行的参数。显然,四个单元测试中的一个失败了。
在顶部的工具栏中,有一些按钮可帮助浏览单元测试和结果。下拉列表中包含了生成单元测试的每个方法。屏幕显示只有一个方法,所以如果在执行IntelliTest之前选择了一个类声明,就需要从列表中选择一个不同的方法。
右边的下拉列表是一个按钮,单击它会进入单元测试的定义。默认情况下,从内存中生成、编译和运行单元测试。解决方案中没有添加项目。然而,如果单击Go to Definition按钮,就会添加一个单元测试项目,并打开单元测试代码文件,以供修改。此时,如果想修改生成的单元测试,就可以这样做,未来执行IntelliTest将尊重和保存现在进行的修改。
为了解IntelliTest过程因生成这些测试而进行的分析级别,考虑图11-13,它更完全地显示了person参数值。

图11-13
如图11-14所示是生成的单元测试的第二个视图。为了得到这个视图,在对话框中间的Views下拉框中选择Events选项。

图11-14
这个视图包含生成单元测试时发生的一个事件列表。如果IntelliTest有问题,这个事件就以粗体显示,左边还会显示一个警告符号。图11-14中的第一行就包含这样一个事件。这种情况下,生成过程不得不猜测如何创建Subscription类。当选择该行时,右边是IntelliTest决定用于解决问题的方式。如果对解决方案满意,就单击Suppress按钮(工具栏中Warnings的左边),禁用未来的警告。但是如果想修改创建类的方式,就单击修复Fix按钮(也在工具栏中Warnings的左边)。这会增加工厂代码,用于给单元测试项目创建Subscription类,并允许根据需要编辑它。
如果是刚开始编写单元测试,或使用测试目前没有覆盖的旧代码,IntelliTest的功能就是一个有效的补充。除了帮助生成一套得体全面的单元测试集之外,IntelliTest还可以帮助从头开始创建自己的单元测试。但注意,不要依赖生成的测试。虽然它们能很好地识别边界情况,但它们并不彻底。生成的测试可能无法覆盖一些业务逻辑。所以不要把它们作为一个完整的单元测试集。相反,应把它们作为一个很好的起点,编写更多自己的单元测试。