** NUnit Cookbook **
本文讲述了如何用 NUnit 书写和组织测试代码的步骤。
简单的 Test Case
书写测试代码的步骤:
1. 创建 TestCase 的一个实例;
2. Override 方法 RunTest ();
3. 如要检查某值,则调用 Assert 。
例如,测试“两个 Money 对象之和与包含它们之和的对象相等”的测试代码如下:
public void TestSimpleAdd() {
Money m12CHF= new Money(12, "CHF");
Money m14CHF= new Money(14, "CHF");
Money expected= new Money(26, "CHF");
Money result= m12CHF.Add(m14CHF);
Assert(expected.Equals(result));
}
如果要写的测试与以前写的测试非常像,那么就写一个 Fixture 来代替。如果想在一个测试中运行更多的东西,就创建一个 Suite 。
Fixture
如果有两个或两个以上的测试作用于相同或类似的对象集,我们该怎么办呢?测试作用于一个已知的对象集,这个对象集被称为 fixture 。一般建立这个 fixture 的时间比实际测试的时间多得多。
当有个公共的 fixture 时,我们可以这么做:
1. 创建 TestCase 的子类。
2. 为 fixture 的每部分加入一个实例变量。
3. Override SetUp() 初始化这些变量。
4. Override TearDown() 释放任何在 SetUp 中分配的永久资源。
例如,编写用来与 12 Swiss Francs , 14 Swiss Francs 和 28 US Dollars 不同组合一起工作的 TestCase 时,首先创建一个 fixture :
public class MoneyTest: TestCase {
private Money f12CHF;
private Money f14CHF;
private Money f28USD;
protected override void SetUp() {
f12CHF= new Money(12, "CHF");
f14CHF= new Money(14, "CHF");
f28USD= new Money(28, "USD");
}
}
一旦准备好 Fixture ,就可书写任意多的测试用例。
Test Case
当有一个 Fixture 如何书写和调用一个独立的 Test Case 呢?书写一个没有的 fixture 测试用例是非常简单的——只需在 TestCase 的一个子类中 override RunTest 。为一个 Fixture 书写测试用例是同样的方法,通过为 set up 代码制造一个 TestCase 的子类,然后为每个独立的测试用例制造不同的子类。然而,不久你就会注意到这些代码中的大部分成为了语法的牺牲品。
NUnit 为书写一个基于 Fixture 的测试提供了简明的方法:
1. 在 fixture 类中书写一个 public 的测试方法。在此,必须确保这个方法是 public 的,否则它将不能通过 reflection 被调用。
2. 创建这个 TestCase 的一个实例,并把这个测试方法的名字传给它的 constructor 。
例如,测试一个 Money 对象与另一个 MoneyBag 的和:
public void TestMoneyMoneyBag() {
// [12 CHF] + [14 CHF] + [28 USD] == {[26 CHF][28 USD]}
Money bag[]= { new Money(26, "CHF"), new Money(28, "USD") };
MoneyBag expected= new MoneyBag(bag);
AssertEquals(expected, f12CHF.Add(f28USD.Add(f14CHF)));
}
创建 MoneyTest 的实例:
new MoneyTest("TestMoneyMoneyBag")
当这个测试运行起来时,测试会查找测试方法的名字并调用它。一旦有多个测试,就可以把他们组织成一个 Suite 。
Suite
如何一次进行多个测试? NUnit 提供了 TestSuite ,它可以一次运行任意数目的测试。例如,运行一个单独的测试用例:
TestResult result= (new MoneyTest("TestMoneyMoneyBag")).Run();
创建一个有两个测试用例的 suite 并且一次运行它们:
TestSuite suite= new TestSuite();
suite.AddTest(new MoneyTest("TestMoneyEquals"));
suite.AddTest(new MoneyTest("TestSimpleAdd"));
TestResult result= suite.Run();
另一种方法是让 NUnit 从一个 TestCase 吸取出一个 suite ,只需把你的 TestCase 传给 TestSuite 的 constructor 即可:
TestSuite suite= new TestSuite(typeof(MoneyTest));
TestResult result= suite.Run();
当创建只包含一个测试用例子类的 suite 时,使用手工方法。否则就采用自动方法,它避免了在每增加新的测试用例时都要改变 suite 的创建代码。
TestSuites 并不是只能包含 TestCase 类。它可以包含实现了 ITest 的任意对象。例如,你可以在你的代码中创建一个 TestSuite ,同样我也可以在我的代码中这样做。那么我们就可以创建一个包含它们的 TestSuite 来一次运行它们:
TestSuite suite= new TestSuite();
suite.AddTest(Kent.Suite());
suite.AddTest(Erich.Suite());
TestResult result= suite.Run();
TestRunner
如何运行这些测试并收集结果呢? NUnit 提供了定义 suite 运行和显示结果的工具。为了使你的 suite 对于 TestRunner 时可存取的,必须定义一个返回测试 suite 的 static property Suite 。
例如,在 MoneyTest 中加入以下代码使 MoneyTest suite 对于 TestRunner 可用:
public static ITest Suite {
get {
TestSuite suite= new TestSuite();
suite.addTest(new MoneyTest("TestMoneyEquals"));
suite.addTest(new MoneyTest("TestSimpleAdd"));
return suite;
}
}
如果一个 TestCase 类不定义一个 suite 方法, TestRunner 将自动产生用所有方法来填充的 suite ,并在这些方法名字前加上前缀“ Test ”。 NUnit 提供两种 TestRunner : GUI 和字符版本。
GUI 窗口包含:填写包含测试类的 DLL 或 EXE 名字的文本框;填写在 DLL 或 EXE 中拥有 Suite 属性的类名。如下图:
在 reload 已编译类的动态编程环境中,你可以不需要 NUnit 窗口。在其他环境中,你必须为每次运行不断重启 GUI 版本。这是非常乏味和费时的工作,这在将来的版本中会得到改进。
同样,有一个 NUnit 的批处理接口。为了使用命令行的 NUnit ,可以在系统提示符下键入 NUnitConsole 后跟包含 Suite 属性的类所在的装配体。例如,使用批处理 TestRunner 测试 MoneyTest :
C:\NUnitConsole NUnit.Samples.Money.MoneyTest,NUnitSamples.dll
批处理接口将结果以文本的方式输出。另一个可选方法是在你的 TestCase 类的 main 方法中调用批处理接口。如下:
public static void Main (String[] args) {
NUnit.TextUI.TestRunner.Run(Suite);
}
这样,只需在系统提示符下键入 MoneyTest 就可运行测试。