NUnit的创造者Jim Newkirk公布了一个新的单元测试框架,叫做xUnit.net。这个以NUnit接班人自许的新框架打算消除NUnit的错误和缺点,并打算在框架中加入一些最佳实践和扩展能力。
Jim Newkirk和Brad Wilson这两位xUnit.net的创造者,从NUnit和其他单元测试框架的经验中总结出来以下改进:
- 为每个测试方法产生一个对象实例
- 取消了[SetUp]和[TearDown]
- 取消了[ExpectedException]
- 类似于Aspect的功能
- 减少了自定义属性(Attribute)的数目
- 采用泛型
- 匿名委托
- 可扩展的断言
- 可扩展的测试方法
- 可扩展的测试类
xUnit.net减少了属性(Attributes)的数量,属性被用来控制测试和测试的执行过程。其中有个 [Test]属性用来标出测试方法。跟NUnit、MbUnit和MSTest不同,测试类并没有任何标志。xUnit.net直接在程序集中查找所有公开类的全部公开测试方法。[SetUp]和[TearDown]已经被抛弃,因为它们一般被认为是坏的实践:
xUnit.net团队觉得每项测试分别执行setup和teardown会产生难以理解与除错的测试代码,并且常常导致每一项测试执行之前都要运行一些不必要的代码。
Jim Newkirk曾经在博客上撰文说明为何不应在NUnit中使用SetUp和TearDown:
我对SetUp的不满来自两个方面。第一也是主要的问题是,在我阅读每个测试的时候,我都不得不瞥一眼BeforeTest(),看看在测试中用到的那些值。如果有TearDown方法的话就更糟,这下我要看3个方法。第二个问题是BeforeTest()为所有的测试初始化成员变量,这会让BeforeTest()复杂化而且违反了单一职责原则。
原先[ExpectedException]属性被用来声明希望测试代码抛出的异常,它已被Assert.Throws断言取代。测试集(TestFixture)由ITestFixture接口标出,接口里面有两个方法:BeforeAllTests()和AfterAllTests()。测试超时和暂时跳过某些测试是通过[Test]属性的参数来实现的,并没有单独为此定义属性。MbUnit里面非常受欢迎的[RowTest]和[Row]测试模式也被包括了进来,由[Theory]和[DataViaXxx]实现:
xunit.extensions.dll里附带了对数据驱动测试的支持,被称为Theory。用[Theory](代替[Test])来标记你的测试,再标记上其中一个[DataVia...]属性,用来指出数据的来源。
xUnit.net中的断言的数量也减少了。任何可用基本断言实现其功能的断言都被放弃。另外“is”和“are”(如“AreEqual”或“IsEmpty”)前缀也被去除。xUnit.net网站上提供了NUnit、MbUnit、MSTest与xUnit.net的属性和断言的详细对比。
xUnit.net还用上了.NET 2.0和3.5的新语言特性。它支持使用泛型,因此可以在比较语句中保证类型安全,比如Equal和NotEqual断言。取代了[ExpectedException]属性的Assert.Throws()方法支持匿名委托和lambda表达式,因此代码更加紧凑也更具可读性:
Assert.Throws<InvalidOperationException> (delegate { operation(); }); // .NET 2.0
Assert.Throws<InvalidOperationException> (() => operation()); // .NET 3.5
测试类、测试方法和断言都很容易扩展。IComparer<T>接口让用户能够扩展Equal、NotEqual之类的功能。xUnit.net支持创建测试模式,测试模式控制着测试如何调用和执行。最后,用户还可以通过扩展现有的TestRunner或者自己新建TestRunner来控制测试套件和测试类的执行。
xUnit.net的创造者们显然认为他们这个开源框架会成为NUnit的接班人。而Roy Osherove觉得xUnit.net还不够成熟,未来还有些疑问。
查看英文原文:xUnit.net - Next Generation of Unit Testing Frameworks?