NCover基础:使用 NUnit 和 NCoverExplorer 改进 Json.NET 的测试套件





0/5 (0投票)
掌握 NCover 最简单的方法之一就是深入代码并改进测试,因此在本文中,我们将着眼于改进开源项目 Json.NET 的测试质量。
NCover基础:使用 NUnit 和 NCoverExplorer 改进 Json.NET 的测试套件
掌握 NCover 最简单的方法之一就是深入代码并改进测试,因此本周我们将着眼于改进开源项目 Json.NET 的测试质量。Json.NET 可在 CodePlex 上获得,在此处。Json.NET 是一个用于从 .NET 读取和写入 JSON 的工具,其中包括 JsonSerializer,可轻松将 .NET 对象序列化为 Json。
Json 是 JavaScript Object Notation 的缩写,是 AJAX 开发人员在浏览器和 Web 服务器之间通信的一种方式,并且越来越多地成为 Web 服务开发人员在各种 Web 服务客户端和 Web 服务器之间通信的一种方式。您可以在 Introducing JSON 中了解更多关于 Json 的信息。
我们将首先通过 NCoverExplorer 编译和运行 Json.NET 的测试,以可视化代码覆盖率,然后着手通过提高项目的代码覆盖率来实际改进 Json.NET 的测试套件的质量。
在本文中,我们将使用 Visual Studio 2005、NUnit,当然还有 NCover。如果您使用 Visual Studio 以外的其他工具来构建项目,只要您能够编译 Json.NET 项目,应该都没问题。如果您尚未安装 NUnit,可以从 Nunit 主页下载最新的 MSI 安装程序,进行安装,并将 NUnit 的 bin 目录添加到您的路径中。NCover 可以从 此处下载,您需要付费或许可证才能完成本文中概述的步骤。
构建 Json.NET 并在 NUnit 中进行测试
构建 Json.NET 非常简单。从 Json.NET 网站下载项目的源代码。本文将使用版本 1.3.1。源代码包含在 1.3.1 版本中,您可以从 此处下载。下载代码后,将其解压缩到硬盘驱动器,然后在 Visual Studio 2005 中打开位于 Src\Newtonsoft.Json.sln 的解决方案文件。
构建项目就像在 Visual Studio 中点击 Build -> Build Solution 一样简单。片刻之后,您将在 Visual Studio 的 Error List 中看到一些警告,但构建应该会成功完成。
现在解决方案已构建完成,让我们在 NUnit 中进行测试,以确保所有测试都成功。打开一个控制台窗口,然后 cd 到解压缩 Json.NET 的位置。接下来,cd 到 Src\Newtonsoft.Json.Tests\bin\Debug 文件夹,您的构建输出应该在此处。列出目录中的文件应显示几个 DLL 和 PDB 文件,以及几个 XML 文档。
要使用 NUnit 测试 Json.NET,请在命令行中执行以下命令
nunit-console Newtonsoft.Json.Tests.dll
您将看到一些输出滚动显示,因为测试正在执行,并且应该看到……等一下!有一个测试失败了。让我们在继续之前先修复它。
您会注意到测试失败的输出应该看起来像这样

我们可以立即判断出失败很可能是因为 Json.NET 的开发人员针对他的时区编写了测试,而不是针对运行测试的时区,因此在 XmlNodeConverterTest.cs 文件的第 339 行左右进行一些更改应该可以解决问题。
所以,让我们在第 337 行之前添加几行代码,以获取我们自己时区的 DateTime
// Get a DateTime set to our current locale to put into our expected XML DateTime dt = new DateTime(1970, 1, 1); dt = dt.AddMilliseconds(954374400000);
然后更新原来的第 337 行,在旧的序列化 DateTime
的位置序列化我们创建的 DateTime
string expected = @"<?xml version=""1.0"" standalone=""no""?>" + @"<root><person id=""1""><Float>2.5</Float><Integer>99</Integer></person>" + @"<person id=""2""><Boolean>true</Boolean><date>" + XmlConvert.ToString(dt, "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz") + @"</date></person></root>";
现在重新构建项目,并在控制台中再次通过 NUnit 运行它,您应该会看到它成功完成。
使用 NCoverExplorer 收集覆盖率数据
安装 NCover 应该会在您的开始菜单中添加一个 NCoverExplorer 的快捷方式,请打开它。然后,单击工具栏上的 Run NCover 按钮,或从 File 菜单中选择 Run NCover...。您将看到 NCoverExplorer Run 对话框。

运行对话框为您提供了 NCover.Console 命令行提供的所有选项。我们将在 Application to Profile(要分析的应用程序)页面上设置以下选项
- 在计算机上的 NUnit\bin 文件夹中选择 nunit-console.exe 可执行文件(它通常安装在 Program Files 中)。
- 在 working directory(工作目录)字段中,输入 Json.NET 项目中 Src\Newtonsoft.Json.Tests\bin\Debug 文件夹的路径。
- 在 application arguments(应用程序参数)字段中,输入 nunit-console 的参数。在本例中,它将是 "Newtonsoft.Json.Tests.dll /noshadow"。
/noshadow
标志只是告诉 NUnit 不要对它正在测试的程序集进行阴影复制。阴影复制有时会给 NUnit 带来问题,因此我们建议您始终在关闭它的情况下进行测试。
此外,请确保 Run 对话框左下角的 "Close window & load coverage file"(关闭窗口并加载覆盖率文件)复选框未选中,以便我们可以在 NCover 完成后查看其输出。
现在单击对话框右下角的 Run 按钮,您应该会看到 Run 对话框中开始滚动输出。输出的前几行显示了 NCover 设置,然后您应该会注意到 NUnit 的输出,就像我们之前运行 NUnit 测试时显示的那样。最后,您应该会看到覆盖率数据的摘要以及 NUnit 的返回代码(应为 0)。
查看覆盖率并改进测试套件
现在您已经收集了应用程序的覆盖率数据,请单击 Run 对话框中的 "Close"(关闭)按钮以显示 NCoverExplorer 主界面。您会注意到在最左边的窗口中可以看到两个项目命名空间 Newtonsoft.Json
和 Newtonsoft.Json.Tests
。您还可以看到命名空间旁边的百分比。这些百分比表示命名空间中在测试执行期间被访问的代码行的百分比。

展开 Newtonsoft.Json
命名空间将显示命名空间内的命名空间。展开这些命名空间将显示类,展开类将显示方法。单击类或方法将带我们到声明该类或方法的源文件。您将在源视图中看到,在测试过程中未访问的代码行以红色突出显示,访问过的行以绿色突出显示。
我们将以命名空间中几个更容易覆盖的方法为目标,并尝试将其覆盖率提高到 100%。让我们从 Newtonsoft.Json.JsonReader
类中的 ParseProperty
方法开始。它只有一行代码未被覆盖——第 380 行。下面显示了第 380 行周围的代码,并突出显示了第 380 行以示强调
if (ValidIdentifierChar(_currentChar))
{
ParseUnquotedProperty();
}
else if (_currentChar == '"' || _currentChar == '\'')
{
ParseQuotedProperty(_currentChar);
}
else
{
throw new JsonReaderException("Invalid property identifier character: " +
_currentChar);
}
我们可以很容易地看出,只有当 Json 属性未返回 true(表示属性应以字母、数字、下划线或美元符号开头)或不匹配 " 或 ' 时,该行才会被到达。因此,让我们编写一个快速测试,该测试创建一个这样一个无效的属性,并通过 JsonReader 尝试解析它。我们的测试应检查是否抛出了 JsonReaderException
。
我们将向 JsonReaderTest.cs 的底部添加一个测试,其代码如下,以覆盖该异常的抛出
[Test]
[ExpectedException(typeof(JsonReaderException))]
public void TestInvalidPropertyName()
{
string input = @"{@CPU: 'Intel'}";
StringReader sr = new StringReader(input);
using (JsonReader jsonReader = new JsonReader(sr))
{
// just read until the reader is exhausted
while (jsonReader.Read()) { };
}
}
该测试基本上是创建一个带有无效标识符 (@CPU) 的 Json,然后使用 JsonReader 读取 Json,直到发生异常。但是,我们怎么知道异常是在正确的位置抛出的呢?
好了,构建您的项目并返回 NCover Explorer。再次打开 Run 对话框,然后单击 run 按钮通过 NCover 运行测试。在测试执行完成后,并且您已确认它们都已成功,请关闭 run 对话框,然后单击 File -> Reload 加载执行的新覆盖率数据。您应该会看到 JsonReader.cs 的第 380 行现在已被覆盖,因此我们知道我们的更改导致该行被访问,并且异常已抛出,因为我们的测试通过了。
一个更难的例子
在我们完成本文之前,我们将再改进一个 JsonReader 中的方法。让我们关注一个完全未被覆盖的方法。在 NCoverExplorer 中稍作挖掘,我们发现私有方法 ParseComment(从第 724 行开始)完全未被覆盖。让我们专注于该方法。
让我们先从一个包含 Json 注释的基线测试开始。这将覆盖 ParseComment
的一些行,并让我们知道我们正走在正确的道路上。我添加了以下测试,该测试会解析包含注释的 Json
// Tests a comment [Test] public void TestParseComment() { string input = @"{CPU: 'Intel', /* Some Comment */ Manufacturer: 'Dell'}"; StringReader sr = new StringReader(input); using (JsonReader jsonReader = new JsonReader(sr)) { // just read until the reader is exhausted while (jsonReader.Read()) { }; } }
使用 NCoverExplorer 运行它,您应该会看到 ParseComment
的大多数行现在已被覆盖。看起来我们正走在正确的道路上。现在,让我们覆盖一些未覆盖的条件。
方法中的第一个未覆盖代码块,第 744 行和第 745 行,是处理注释中间的星号。当 Json.NET 解析注释时,它会查找星号,然后如果星号后面跟着一个斜杠,它就会完成注释处理。但是,如果星号后面没有斜杠,它只会将斜杠添加到缓冲区并继续。因此,让我们在注释的中间添加一个没有尾随斜杠的星号,这应该可以覆盖该条件。我们只需更改我们刚写的第一个测试的第一行
string input = @"{CPU: 'Intel', /* Some * Comment */ Manufacturer: 'Dell'}";
通过 NCoverExplorer 运行该更改,您将看到方法中只剩下最后一行代码(第 757 行)需要覆盖,我们就完成了。我认为下一行需要自己的测试。该行看起来是在有人在代码中输入了没有后续星号的斜杠时抛出异常,这基本上意味着他们输入了开始注释标记的一半。
以下测试应该可以做到
// Tests a comment with a missing opening asterisk
[Test]
[ExpectedException(typeof(JsonReaderException))]
public void TestParseCommentMissingOpeningAsterisk()
{
string input =
@"{CPU: 'Intel', / Some Comment With Missing Asterisk */ Manufacturer: 'Dell'}";
StringReader sr = new StringReader(input);
using (JsonReader jsonReader = new JsonReader(sr))
{
// just read until the reader is exhausted
while (jsonReader.Read()) { };
}
}
通过 NCoverExplorer 运行它,您会看到它确实覆盖了该方法的最后一行未覆盖的代码。
结论
在本文中,我们看到了使用 NCoverExplorer 改进 NUnit 测试质量是多么容易。现在我们可以确信 JsonReader
类中的 ParseComment
和 ParseProperty
方法已得到彻底测试。一个很好的练习是让 JsonReader
类达到 100% 的覆盖率。
磨练编程技能的最好方法就是阅读他人的代码,甚至更好的是改进他们的代码。养成习惯,找到一些您想参与的开源项目,并帮助它们达到 100% 的覆盖率。当您改进了项目中的几个类后,您应该会看到对该项目有了扎实的理解,并且已准备好添加新功能。
Json.NET 的所有代码均根据以下许可授权
Copyright (c) 2007 James Newton-King 授予任何获得本软件及相关文档文件(“软件”)副本的人员免费的许可,允许其处理本软件,不受限制,包括但不限于使用、复制、修改、合并、发布、分发、转授和/或出售本软件副本的权利,以及允许接收本软件的人员这样做,但需满足以下条件:上述版权声明和本许可声明应包含在本软件所有副本或实质性部分中。本软件按“原样”提供,不附带任何形式的保证,明示或暗示,包括但不限于适销性、特定用途的适用性和非侵权性的保证。在任何情况下,作者或版权持有人均不对因合同、侵权行为或其他行为引起的,或以其他方式与本软件或软件的使用或其他交易相关的任何索赔、损害赔偿或其他责任负责。