C#单元测试工具
C#单元测试相关的开源软件中常用的有 NUnit、 XUnit和MsTest。
MsTest
1) 基本介绍
MSTest是一款由微软公司开发的单元测试框架,它能够很好地被应用在Visual Studio中,并且集成在了Visual Studio单元测试框架中,操作简单,上手容易。
MsTest中核心的概念有Test Class(测试类)、Test Method测试方法、断言和初始化及清理方法。
Test Class:通过使用[TestClass]属性装饰类来声明测试类。该属性用于标识包含测试方法的类,最佳做法规定测试类应仅包含单元测试代码。
Test Method:通过使用[TestMethod]属性装饰单元测试方法来声明测试方法。该属性用于标识包含单元测试代码的方法,最佳实践指出,单元测试方法应仅包含单元测试代码。
断言:断言是一段代码,当运行于测试一个条件或行为针对预期的结果。通过调用Assert类中的方法来执行。
初始化和清理方法:初始化和清理方法用于在运行之前准备单元测试,并在执行单元测试之后进行清除。初始化方法通过用[TestInitialize]属性装饰初始化方法来声明,而清理方法通过用[TestCleanup]属性声明清理方法。
支持为测试用例设置分类,执行时执行指定分类的测试方法:[TestCategory]
支持在一个或多个测试方法执行前后进行相关的准备、清理活动:[TestInitialize]和[TestCleanup]
支持为测试用例设置参数:[DataRow]
提供断言方法,判定期望值和实际值是否一致
支持使用断言等方式,对返回异常的测试用例进行异常判断:[ExpectedException]
图2-1 MSTest中带参及异常判断实例
支持通过注解等方式跳过执行带有该注解的测试用例:[Ignore]
支持设置超时时间,通过在TestMethod中的[Timeout]属性可以设置单独测试case的超时时间;也可以在.runSettings配置文件中为所有case设置全局的超时时间。
图2-2 MSTest中timeout属性实例
NUnit
框架介绍
(1)基本介绍
NUnit 是专门针对于.NET 的自动化单元测试框架,是 XUnit 家族的一个成员,最初是由Java的单元测是框架JUnit 而来,作者最终用C#对其进行重新编写,NUnit完全由C# 编写,使其更加符合C#习惯,并充分利用了.NET中反射、客户属性等特性。因此,该工具具有丰富的单元测试历史的同时,也具有适当的C#风格。
由于其独立的历史,NUnit还具有与其他工具良好交互的特点,并且在支持多种平台,包括:.NET Core、Xamarin Mobile、Compact Framework及Silverlight等。NUnit在快速测试运行方面也享有盛誉,并且还具有一些不错的附加功能,例如允指定给定测试的多个输入等。
NUnit采用分层体系架构,主要有三层:测试运行器层(Test Runner)、测试引擎层(Test Engine)和框架层(Framework),其中,Test Runner层主要包含各种运行程序,包括独立程序和在其它程序下运行的任务或者插件;Test Engine层则是NUnit平台的核心,它提供公共API,供希望查找,加载和运行测试并显示测试结果的应用程序使用;Framework层主要是为了兼容各个版本的NUnit程序。
NUnit中主要有三个抽象类:TestFixtureBuilderAttribute、TestCaseBuilderAttribute和IncludeExcludeAttribute。
TestFixtureBuilderAttribute是任何知道如何从所提供的类中构建某种测试fixture的属性的基类,testfixture是指基于用户类的任何测试。
TestCaseBuilderAttribute是任何知道如何从给定方法构建测试用例的属性的基类。测试用例可以是简单的(没有参数)也可以是参数化的(接受参数),并且总是基于MethodInfo。
IncludeExcludeAttribute是任何用于根据字符串属性include、exclude和Reason来决定是在当前运行中包含测试还是排除的属性的基类,抽象类是使这些属性可供派生类使用,派生类负责对它们采取操作。
在使用方面,NUnit可以通过控制台或自己独立的GUI来运行,在使用Visual Studio作为IDE时,NUnit也提供了相应的适配器,可以更好地和Visual Studio搭配使用。
(2)工具特点
NUnit2中有包含GUI界面;
支持为测试用例设置分类,执行时执行指定分类的测试方法:使用[Category]属性;
支持在一个或多个测试方法执行前后进行相关的准备、清理活动:[SetUp]和[TearDown];
提供断言方法,如果断言失败,则方法调用不会有值返回并报告错误。如果一个测试包含多个断言,那么在某次断言失败之后就终止,其后的任何断言都不会执行;
支持为测试用例设置参数:[TestCase]
图2-3 NUnit带参测试方法实例
可以指定测试用例的执行顺序:[Order]
支持使用断言等方式,对返回异常的测试用例进行异常判断:Assert.That
图2-4 NUnit排序及异常判断方法实例
支持通过注解等方式跳过执行带有该注解的测试用例:[Ignore("Method is ignored")]
支持设置超时时间,[Timeout]、[MaxTime]。[MaxTime] 标记测试用例的最大执行时间,超时时报错但不取消测试;[Timeout] 标记测试用例的超时时间,超时中断测试。
TestSuite :UNIT3之后取消该属性,因为namespace也可以实现相同的功能。
支持对对接主流的代码覆盖率工具,执行完单元测试用例后自动生成覆盖率报告。
框架介绍
(1)基本介绍
XUnit .NET是一个开源的的单元测试工具,由NUnit v2的原始发明者编写,支持C#,F# ,VB.NET版以及其他.NET语言,由.NET基金会支持,它采用了一种非常独特、现代和灵活的单元测试方法。
XUnit .NET强调编写具有较高的可读性,简单性的单元测试,与其它单元测试框架相比,有一些独特的地方:
XUnit比其他.Net单元测试框架更加灵活和可扩展,它允许创建新的属性来控制测试。XUnit支持两种类型的测试,[Fact]和[Theory],[Fact]通常用来测试不需要参数的方法,并且在XUnit中,用[Skip]属性代替了[Ignore],并要求指定跳过该测试的原因;[Theory]支持数据驱动的测试,可以用[InlineData]属性实现参数的传递,并支持多次执行同一个方法,是XUnit可扩展性强的一个重要体现。
图2-5 http://XUnit.NET带参测试方法实例
XUnit支持更好地进行隔离测试。与其它测试框架不同,在xUnit中,每个测试方法运行后都会进行实例化操作,执行后释放相应的空间,测试之间更加独立,可以以任何顺序执行测试,而不必担心一个测试对其他测试的影响,消除了不同测试方法之间的依赖性。
XUnit取消了[SetUp]和[TearDown]方法,而采用构造函数进行初始化,使用IDisposable进行测试类的后处理等操作,让每个测试对其需要的内容进行初始化。
(2) 工具特点
支持为测试用例设置分类,执行时执行指定分类的测试方法:[Trait("Category","UI")];
支持为测试用例设置参数:[Theory] [InilineData];
支持使用断言等方式,对返回异常的测试用例进行异常判断:Assert.Throws.Exception,长期使用[ExpectedException]会发现各种问题。首先,它没有具体说明应该在哪一行代码中引发异常,这会导致微妙且难以跟踪的失败,这些失败会在通过测试时显示出来。其次,由于处理不在测试的常规代码流程之内,因此它没有提供机会全面检查异常本身的详细信息。Assert.Throws允许您测试一组特定的代码以引发异常,并在成功期间返回异常,以便您可以针对异常实例本身编写进一步的断言。
图2-6 XUnit异常判断实例
支持通过注解等方式跳过执行带有该注解的测试用例,[Fact(Skip="reason")]
支持设置超时时间,[Fact(Timeout =10)]
本次调研重点研究的三款C#单元测试工具(MsTest、NUnit、XUnit)来说,使用区别度并不是很大,具体如下:
MsTest作为内置的visual studio测试工具来讲,操作简单,易于使用;另外,如果已经使用visual studio作为编译器,不用做任何的安装即可使用,也是其较为明显的优点之一。但是其也存在在带参测试时不能同时支持异常判断,以及无法对测试用例排序等缺点。
NUnit作为比较成熟的C#单元测试工具,好处包括可以按名称空间进行测试分组,添加测试用例注释(使用相同的参数多次运行相同的测试)及对测试用例排序等功能,并且它与Opencover和Report Generator进行覆盖分析的效果很好。主要的缺点是它没有像MSTest那样集成,但是通过Nuget现在在visual studio中使用NUnit已经成为一件比较容易的事情。NUnit还有一个不同于其它测试工具的特点是NUnit2中有自己的GUI,可以不通过VS来看单元测试结果,但是如上所说,GUI只在NUnit2中提供,而现在普遍使用的都是NUnit3。
XUnit作为NUnit的进阶简化版,是一种和NUnit及其相似的简单现代的单元测试框架。XUnit不同于其它测试工具的特点主要有两个:一是取消了单元测试框架中的前后处理方法,为每个测试方法都创建测试类的新实例,即提高了测试用例之间的隔离性;二是用断言替代了属性的方式来捕捉异常,不采用Attribute的方式来捕捉异常有两方面的好处:在代码中直接断言(Assert)能捕捉到更多种类的异常;遵守Arrange-Act-Assert (or "3A") 模式:即测试命名上“范围-作用-断言”规范。但是正是由于其简化的特性,其缺点也显而易见,即一些高阶的测试可能无法用XUnit完成,并且和NUnit一样,XUnit与VS的集成没有MsTest那么自然。
总结
本次调研重点测评了三款C#开源单元测试工具,对其特性及基本使用进行了介绍。其实在开源社区蓬勃发展的今天,众多开源工具之间的区别也通过很多次迭代渐渐在缩小,如本次重点调研的三款工具虽各有优势和劣势,但是差异已经不再那么明显,大家在使用时结合自身的业务背景来选择合适的工具即可。