NUnit 和 TDD 入门






4.81/5 (39投票s)
本文将介绍 NUnit 和 TDD
引言
NUnit 是 .NET 应用程序的优秀单元测试工具。在本文中,我将解释 NUnit 的基础知识,并指导您逐步创建示例单元测试。但是,如果您正在寻找单元测试,您还应该了解测试驱动开发的概念。反之亦然,如果 TDD 是您的目标,您也必须浏览 NUnit。为了真正发挥单元测试的优势,TDD 是最好的方法。因此,本文还涵盖了 TDD 的概念。
什么是单元测试
单元测试是一种开发过程,程序员在开发软件时创建测试。这些测试是简单简短的测试,用于测试其代码的特定单元或模块的功能,例如类或函数。单元测试的一般行为是它向类发送预定义的消息并验证响应。是的,您没听错!开发者负责单元测试,这意味着您需要编写额外的代码!大约 20% 的额外工作!等等,好处远不止这些。
让我们先了解 NUnit
NUnit 是一个单元测试框架,使用 C# 开发。它使用基于属性的编程模型。它提供了漂亮的、干净的 GUI 以及用于测试程序集的控制台应用程序。稍后我们将详细介绍。首先,让我们创建一个示例测试。
这里我以 `Person` 类为例。所以在项目中创建一个如下的类。
public class Person
{
public string Lname
{ get; set; }
public string Fname
{ get; set; }
public string Mname
{ get; set; }
public string Address
{ get; set; }
public string Email
{ get; set; }
public string Phone
{ get; set; }
public string GetFullName()
{
if(string.IsNullOrEmpty(Lname))
throw new MissingFieldException("Lname is empty");
return string.Format("{0} {1} {2}",Fname,Mname,Lname);
}
}
步骤 1:从已安装的 nunit 应用程序的 bin 目录中添加对 `nunit.framework.dll` 的引用。
步骤 2:创建一个类来编写您的测试。假设您想测试一个“Person
”类。将您的测试类命名为 `TestPerson`。最佳实践:使用单独的类库。为应用程序中的每个类使用单独的类进行测试。
步骤 3:为类添加 `Attribute`。
测试类应具有“Test Fixture
”属性。
让我们理解这个属性
[TestFixture]
- 将要包含测试代码的类应为此属性打上标签。
- 当您将此属性附加到项目中的一个类时,Test Runner 应用程序将扫描它以查找测试方法。
- 类必须有一个 `public` 默认构造函数。
代码片段
[TestFixture]
public class TestPerson
步骤 4:编写测试
创建一个名为 `testFullName()` 的方法。此方法将包含测试“GetFullName()
”方法的代码。
此方法应标记为 `Attribute [Test]`。任何包含执行测试的实际代码的方法都应标记为该属性。签名必须是:`public void
现在,在此方法中实现以下代码
using NUnit.Framework;
namespace NunitExample
{
[TestFixture]
public class TestPerson
{
[Test]
public void TestFullName()
{
Person person = new Person ();
person.lname = "Doe";
person.mname = "Roe";
person.fname = "John";
string actual = person.GetFullName();
string expected = "John Roe Doe";
Assert.AreEqual(expected, actual,
”The GetFullName returned a different Value”);
}
}
}
让我们来理解这段代码:测试方法为 `Person` 类的属性分配固定值。现在我们要检查 `GetFullName()` 是否正常工作。因此,我们将返回的值与我们预期的值进行比较。如果匹配,测试通过,否则测试失败。
为了比较结果,我们使用 Nunit Framework 的“Assert
”类。断言是任何单元测试框架的核心。在这里,我们使用“AreEqual
”方法来比较两个结果。
如您所见,`AreEqual()` 需要 3 个参数。第三个是可选的。前两个是我们想要比较的值,第三个是在测试失败时显示的帮助信息。
`AreEqual` 方法有许多重载,因此您可以比较不同的数据类型。
`Assert` 类有许多不同的方法,支持集合、异常、目录、文件等。我们在这里不一一介绍。您可以在官方 Nunit 网站上轻松了解所有这些。
步骤 5:运行代码。
编译您的代码。
让我们使用 GUI 来运行代码。打开 GUI,从文件菜单中选择“New project”。为新项目保存一个名称。
然后转到项目菜单,选择“Add Assembly”,然后选择包含您的测试类的程序集。您将看到测试类及其测试方法显示在窗口的左侧面板中。
选择 `PersonTest` 类,然后单击 Run。此类的所有测试都将被运行。

当您看到所有内容都变成绿色时,就是庆祝的时候了!您所有的测试都已通过。当您仔细查看屏幕时,您会发现它显示了各种参数,例如哪些测试已通过、失败、执行测试所花费的时间等。
现在,在测试方法中更改上面的代码,以获得无效结果。例如:
Assert.AreEqual(“abcd”, “actual” ,”The GetFullName returned a different Value”).
重新构建程序集,然后在 Nunit GUI 中,单击 File->Reload tests。
现在,再次运行,看看测试失败时屏幕是什么样的。

看到红色,它还显示了您指定的帮助信息。
好了,现在您知道如何运行和编写单元测试代码了。让我们快速浏览一下其他一些重要且非常有用的属性。
一些重要的属性
Setup 属性
[SetUp]
public void init()
{
Person person = new Person();
}
如您在代码中看到的,`Setup` 属性应用于任何初始化类型的函数。在执行测试之前必须执行的任何代码都可以放在用 `[Setup]` 标记的函数中。这使您不必在每个测试中重复这些代码行。请仔细注意,这段代码是在每个测试之前执行的。
Tear Down
此属性与 `Setup` 属性完全相反。这段代码是在每个代码执行之后执行的。例如,在此方法中,您可以编写代码来关闭任何 `FileSystem` 对象或数据库连接。
Exception Expected
有时,我们可能希望在特定场景下测试某个方法是否会抛出异常。我们可以使用此属性来测试这一点。
示例
[Test]
[ExpectedException(typeof(MissingFieldException))]
public void TestFullNameForException()
{
Person person = new Person();
person.Lname = "";
person.Mname = "Roe";
person.Fname = "John";
string actual = person.GetFullName();
}
这段代码没有任何 `Assert` 语句。如果调用“GetFullName()
”时抛出了“MissingFieldException
”,则此测试将通过。如果没有抛出异常,测试将失败。
Ignore
您想暂时跳过的任何测试都可以用此属性标记。
一些显而易见的优势
- 害怕改变?不再是了!
- 代码中的任何更改都会立即产生已知的影响。
- “测试不是你“做”的东西,而是你“写”并运行一次、两次、三次等的东西。”
最佳实践:可以使用 Nant 等工具进行自动计划构建。每次构建时,Nant 都会运行 Nunit 测试,并将结果生成到 XML 文件中!
测试驱动开发 – TDD
测试驱动的概念可以简单地用以下两句话来概括。
“第一步是快速添加一个测试,基本上只需要足够的代码让它失败。接下来运行您的测试,通常是完整的测试套件,尽管为了速度,您可能会决定只运行一部分,以确保新测试确实失败。然后更新您的功能代码以使其通过新测试。第四步是再次运行您的测试。如果失败,您需要更新您的功能代码并重新测试。一旦测试通过,下一步就是重新开始(您可能首先需要重构设计中任何重复的部分,将 TFD 转换为 TDD)”。

这是一个迭代过程,您会一直进行,直到所有测试都通过。
TDD 的一些已证实的优势
- 单元测试在开发周期的早期发现问题
- 自动化的单元测试套件在两个维度上监视您的代码:时间和空间
- 开发者将不再害怕更改现有代码
- 开发过程变得更加灵活
- 提高您项目的“卡车因子”(Truck Factor)
- 手动测试的需求
- 软件开发将变得更加可预测和可重复
- 更短的开发周期
对阅读本文的项目经理来说,值得关注的一点

绿色图表显示了 TDD 周期,而红色图表显示了传统的先编码后测试的开发方法。
注意
在结束本文之前,还有一个小小的警告
- 所有测试通过并不意味着软件已准备好交付。
- 单元测试不取代传统的系统测试。
即将推出
一旦您开始使用 TDD,您可能会遇到一些挑战。您可能需要实现适当的设计模式和模拟(mocking)才能成功实现单元测试和 TDD。我的下一篇文章将涵盖这些内容。请耐心等待,它很快就会到来。
历史
- 2011 年 2 月 24 日:初始发布