怎么样在.NET环境中使用单元测试工具NUnit?
怎么样在.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,如同下面的范例所示:
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,如同下面的范例所示: