在.NET环境中使用单元测试工具NUnit

简介

编写单元测试是一种验证行为,更是一种设计行为。同样,它更是一种编写文档的行为。编写单元测试避免了相当数量的反馈循环,尤其是功能验证方面的反馈循环。

虽然由程序开发人员自己写 Unit Tests( 单元测试 ) 来测试自己写的程序代码已经行之有年,但是大部分的 Unit Tests 都是写在主要的程序代码已经设计好、写好之后。大部分的程序开发人员都有相同的的经验,在主要程序代码写好之后再来加入 Unit Test 是一项困难的工作,而且在时间的压力之下 Unit Test 通常是第一个被跳过的步骤.本篇文章介绍的是一个.NET平台的单元测试工具NUnit。

什么是 Unit Tests(单元测试)?

在程序设计过程中会有许多种测试,单元只是其中的一种,单元测试并不能保证程序是完美无缺的,但是在所有的测试中,单元测试是第一个环节,也是最重要的一个环节。单元测试是一种由程序员自行测试的工作。简单点说,单元测试就是测试代码撰写者依据其所设想的方式执行是否产生了预期的结果。关于单元测试的重要性已经有许多文章做了很多深入的分析,这里就不再赘述。 NUnit 是一个为 Net 准备的自动化单元测试框架,它的作用就是帮助你方便的完成单元测试工作,同鼎鼎有名的 JUnit 一样,都是 xUnit 家族的成员。它的下载地址是: http://www.nunit.org

NUnit Framework(NUnit 单元测试框架)简介

本文所讨论的 NUnit 2.1 是一个与它的先祖们 ( 其它的 Framework) 非常不一样的版本。其它的 xUnit 家族版本通常都有一个 base class (基础类),你要写的 test classes( 测试用例 ) 都得 inherit( 继承 ) 自这个 base class 。除此之外,别无他法能够让你写 Unit Tests 。不幸的是,这对很多的程序语言来说就造成很大的限制。比如说, Java 及 C# 就只能允许 single inheritance( 单一继承 ) 。也就是说,如果你想要 refactor( 重构 ) 你的 Unit Tests 程序代码的话,你会遇到一些的限制;除非你引进一些复杂的 inheritance hierarchies( 类别继承层级 ) 。有了 .NET 之后一切又不同了, .NET 引进了一个新的程序开发的概念 ─ Attributes( 属性 ) ,解决了这个烦人的问题。 Attributes 让你可以在你的程序代码之上再加入 metadata( 元数据,描述程序代码的资料 ) 。一般来说 Attributes 不会影响到主要程序代码的执行,其功能是在你所写程序代码之上添加了额外的信息。 Attributes 主要使用在 documenting your code( 注释你的程序代码 ) ,但是 Attributes 也可以用来提供有关 Assembly 的额外信息,其它的程序就算没有见过这个 Assembly ,也可以使用这些信息。这基本上就是 NUnit 2.1 所作的事。在 NUnit 2.1 里面,有一个 Test Runner Application( 负责执行 Unit Tests 的程序 ) ,这个 Test Runner 会扫描你已经 compile( 编译 ) 好的程序代码,并且从 Attribute 里面知道哪些 classes 是 test classes ,哪些 methods 是需要执行的 test methods. 然后, Test Runner 使用 .NET 的 Reflection 技术( 在 .NET Framework中提供了 System.Reflection 命名空间,这样就使得我们可以方便的获得.NET组件的信息。当你想获得正在使用的组件的详细信息,或者在运行期间查询一个组件信息的时候,这个功能将变的十分有用) 来执行这些 test methods 。因为这个原因,你就不再需要让你的 test classes 继承自所谓的 common base class 。你唯一需要作的事,就是使用正确的 Attribute 来描述你的 test classes 及 test methods 。 NUnit 提供了许多不同的 attributes ,让你可以自由的写你想要的 unit tests 。这些 attributes 可以用来定义 test fixtures( 见下一段解释 ) 、 test methods ,以及 setup 及 teardown 的 methods( 预备及善后工作的 methods) 。除此之外,还有其它的 attributes 可以来设定预期发生的 exceptions ,或者要求 Test Runner 跳过某些 test method 不执行。

TestFixture Attribute简介

TestFixture attribute 主要是用在 class 上,其作用是标志该 class 含有需要执行的 test methods 。当你在一个 class 的定义里加上这个 attribute , Test Runner 就会检查该 class ,看看这个 class 是否含有 test methods 。底下这段程序代码示范了如何使用 TestFixture Attribute 。 ( 本文中所有程序代码都是用 C# 写成,但是你应该知道, NUnit 也是用于其它的 .NET 程序语言,包括 VB.NET 。请参见 NUnit 的相关文件。

namespace UnitTestingExamples
{

using System;
using NUnit.Framework;

[TestFixture]
public class SomeTests
{
}
}

使用 TextFixture Attribute 的 class 需要符合另一项唯一附加的限制,就是需要有一个 public 的 default constructor( 或者是没有定义任何的 constructor ,这其实是相同的意思 ) 。

TestFixtureSetUp 和TestFixtureTearDown简介

这两个主要用在 TestFixture 里面,其作用是提供一组函数执行任何测试运行之前( TestFixtureSetUP )和最后一个测试执行后( TestFixtureTearDown )。每一个 TestFixture 只能有一个 TestFixtureSetUp 方法和 TestFixtureTearDown 方法。如果一个以上的 TestFixtureSetUp 和 TestFixtureTearDown 方法,可以通过编译但是不会执行。注意一个 TestFixture 可以拥有一个 TestFixtureSetUp 和一个 SetUp ,也可以拥有一个 TestFixtureTearDown 和一个 TearDown 方法。

TestFixtureSetUp 和 TestFixtureTearDown 被用在不方便使用 SetUp 和 TearDown 方法。

一般情况使用 SetUp 和 TearDown attributes 。

底下这段程序代码示范了如何使用 TestFixtureSetUp/TestFixtureTearDown

namespace UnitTestingExamples
{

using System;
using NUnit.Framework;

[TestFixture]
public class SomeTests
{
[TestFixtureSetUp]

public void RunBeforeAllTests()

{

Console.WriteLine( “TestFixtureSetUp” );

}

[TestFixtureTearDown]

public void RunAfterAllTests()

{

Console.WriteLine( “TestFixtureTearDown” );

}

[SetUp]

public void RunBeforeEachTest()

{

Console.WriteLine( “SetUp” );

}

[TearDown]

public void RunAfterEachTest()

{

Console.WriteLine( “TearDown” );

}

[Test]

public void Test1()

{

Console.WriteLine( “Test1” );

}

}

}

程序的输出将是下面的结果: :

TestFixtureSetUp

SetUp

Test1

TearDown

SetUp

Test2

TearDown

TestFixtureTearDown

如果 Test2 单独执行输出的结果将是:

TestFixtureSetUp

SetUp

Test2

TearDown

TestFixtureTearDown

Test Attribute简介

Test attribute 主要用来标示在 text fixture 中的 method ,表示这个 method 需要被 Test Runner application 所执行。有 Test attribute 的 method 必须是 public 的,并且必须 return void ,也没有任何传入的参数。如果没有符合这些规定,在 Test Runner GUI 之中是不会列出这个 method 的,而且在执行 Unit Test 的时候也不会执行这个 method 。上面的程序代码示范了使用这个 attribute 的方法。

SetUp 和 Teardown Attributes简介

在写 Unit Tests 的时候,有时你会需要在执行每一个 test method 之前 ( 或之后 ) 先作一些预备或善后工作。当然,你可以写一个 private 的 method ,然后在每一个 test method 的一开头或最末端呼叫这个特别的 method 。或者,你可以使用我们要介绍的 SetUp 及 Teardown Attributes 来达到相同的目的。如同这两个 Attributes 的名字的意思,有 Setup Attribute 的 method 会在该 TextFixture 中的每一个 test method 被执行之前先被 Test Runner 所执行,而有 Teardown Attribute 的 method 则会在每一个 test method 被执行之后被 Test Runner 所执行。一般来说, Setup Attribute 及 Teardown Attribute 被用来预备一些必须的 objects( 对象 ) ,例如 database connection 、等等。上面的程序代码示范了使用这个 attribute 的方法。

ExpectedException Attributes简介

有的时候,你希望你的程序在某些特殊的条件下会产生一些特定的 exception 。要用 Unit Test 来测试程序是否如预期的产生 exception ,你可以用一个 try..catch 的程序区段来 catch( 捕捉 ) 这个 exception ,然后再设一个 boolean 的值来证明 exception 的确发生了。这个方法固然可行,但是太花费功夫。事实上,你应该使用这个 ExpectedException attribute 来标示某个 method 应该产生哪一个 exception ,如同下面的范例所示: </FO

Published At
Categories with Web编程
Tagged with
comments powered by Disqus