干货丨这3个C#单元测试工具,到底谁才是王者?用例调用

单元测试(unittesting),是指对软件中的最小可测试单元(函数/模块/类)进行检查和验证。

单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

单元测试从长期来看,可以提高代码质量,减少维护成本,降低重构难度。但是从短期来看,加大了工作量,对于进度紧张的项目中的开发人员来说,可能会成为不少的负担。

单元测试应该遵循以下原则:

可靠性、可维护性、可读性;

尽量避免测试中的逻辑,一个单元测试应该是一系列的方法调用和断言;

避免重复代码;

测试隔离,低耦合,防止不同测试之间的互相影响。

主流C#单元测试工具

我们调研了以下开源C#单元测试工具(开源工具数据来自于GitHub):

测评指标

对C#单元测试工具进行测评主要从功能性及非功能性两部分来进行。其中,功能性测评中包括是否支持测试用例分类、排序等;非功能测评点包括社区活跃度及文档完备性等。

测评环境

工具简介

MsTest

框架介绍

(1)基本介绍

MSTest是一款由微软公司开发的单元测试框架,它能够很好地被应用在VisualStudio中,并且集成在了VisualStudio单元测试框架中,操作简单,上手容易。

从使用的角度来看,如果用户使用的是VisualStudio作为IDE,那么MSTest在对它的集成方面无疑是最方便的,无需下载,无需安装,内置在vs的测试框架模板中。在VS中使用MsTest生成测试项目和新建一个C#项目一样方便;如果用户不使用VS,那么也可以通过命令行执行.exe文件来执行单元测试,但是MsTest不提供自己单独的GUI界面。

MsTest中核心的概念有TestClass(测试类)、TestMethod测试方法、断言和初始化及清理方法。

断言:断言是一段代码,当运行于测试一个条件或行为针对预期的结果。通过调用Assert类中的方法来执行。

许多时候会把VsTest和MsTest混淆,其实这两个概念之间还是有一定区别的。

VsTest是VisualStudio测试平台(VisualStudioTestPlatform)的简称,是一个开放且可扩展的测试平台,可用于运行测试,收集诊断数据和报告结果。VsTest支持运行在各种测试框架中并使用可插拔适配器模型编写的测试。根据用户的选择,所需的测试框架及其相应的适配器可以视情况以vsix或NuGet软件包的形式获取。可以使用测试平台公开的公共API来编写适配器。

MsTest是指微软开发的单元测试框架。目前MsTest最新的版本是MsTestV2,V2的版本依赖于两个包:MSTest.TestFramework和MSTest.TestAdapter,用户在使用时可以通过Nuget下载这两个包来使用MsTest进行单元测试。MsTestV2主要是为了.netcore准备的,也可以在.netframework上运行,并且较V1版本新加入了一些扩展。

下图是VsTest的总体架构图,从图中可以看到,整个VsTest架构体系主要有四个组件:测试运行器、测试执行器、数据收集器和IDE。

其中,测试执行器部分主要包含一个执行测试的引擎,它把发现和执行测试的责任委托给了一些可扩展的测试适配器,允许测试平台基于第三方测试框架发现/执行测试。这将通过相应框架的适配器来完成,该适配器了解如何在该框架中定义测试,并可以运行它们以向测试平台提供结果。例如,MsTest适配器了解MsTest框架中编写的测试,VsTest中就会使用MsTest适配器发现并执行它们。

在图中还可以看到,测试运行器部分还包含一个VsTestconsole,其作用是使用命令行运行不同框架的测试。但是如果是采用MsTest作为测试框架,也可以使用MsTest.exe作为命令行执行的工具。

(2)工具特点

支持为测试用例设置分类,执行时执行指定分类的测试方法:【TestCategory】

支持为测试用例设置参数:[DataRow】

提供断言方法,判定期望值和实际值是否一致

支持使用断言等方式,对返回异常的测试用例进行异常判断:[ExpectedException]

图2-1MSTest中带参及异常判断实例

支持通过注解等方式跳过执行带有该注解的测试用例:[Ignore]

图2-2MSTest中timeout属性实例

NUnit

(1)基本介绍

NUnit是专门针对于.NET的自动化单元测试框架,是XUnit家族的一个成员,最初是由Java的单元测试框架JUnit而来,作者最终用C#对其进行重新编写,NUnit完全由C#编写,使其更加符合C#习惯,并充分利用了.NET中反射、客户属性等特性。因此,该工具具有丰富的单元测试历史的同时,也具有适当的C#风格。

由于其独立的历史,NUnit还具有与其他工具良好交互的特点,并且在支持多种平台,包括:.NETCore、XamarinMobile、CompactFramework及Silverlight等。NUnit在快速测试运行方面也享有盛誉,并且还具有一些不错的附加功能,例如允指定给定测试的多个输入等。

NUnit采用分层体系架构,主要有三层:测试运行器层(TestRunner)、测试引擎层(TestEngine)和框架层(Framework),其中,TestRunner层主要包含各种运行程序,包括独立程序和在其它程序下运行的任务或者插件;TestEngine层则是NUnit平台的核心,它提供公共API,供希望查找,加载和运行测试并显示测试结果的应用程序使用;Framework层主要是为了兼容各个版本的NUnit程序。

NUnit中主要有三个抽象类:TestFixtureBuilderAttribute、TestCaseBuilderAttribute和IncludeExcludeAttribute。

TestFixtureBuilderAttribute是任何知道如何从所提供的类中构建某种测试fixture的属性的基类,testfixture是指基于用户类的任何测试。

TestCaseBuilderAttribute是任何知道如何从给定方法构建测试用例的属性的基类。测试用例可以是简单的(没有参数)也可以是参数化的(接受参数),并且总是基于MethodInfo。

IncludeExcludeAttribute是任何用于根据字符串属性include、exclude和Reason来决定是在当前运行中包含测试还是排除的属性的基类,抽象类是使这些属性可供派生类使用,派生类负责对它们采取操作。

在使用方面,NUnit可以通过控制台或自己独立的GUI来运行,在使用VisualStudio作为IDE时,NUnit也提供了相应的适配器,可以更好地和VisualStudio搭配使用。

(2)工具特点

NUnit2中有包含GUI界面;

支持为测试用例设置分类,执行时执行指定分类的测试方法:使用[Category】属性;

提供断言方法,如果断言失败,则方法调用不会有值返回并报告错误。如果一个测试包含多个断言,那么在某次断言失败之后就终止,其后的任何断言都不会执行;

支持为测试用例设置参数:【TestCase]

图2-3NUnit带参测试方法实例

可以指定测试用例的执行顺序:【Order】

支持使用断言等方式,对返回异常的测试用例进行异常判断:Assert.That

图2-4NUnit排序及异常判断方法实例

支持通过注解等方式跳过执行带有该注解的测试用例:[Ignore(“Methodisignored”)】

TestSuite:UNIT3之后取消该属性,因为namespace也可以实现相同的功能。

支持对接主流的代码覆盖率工具,执行完单元测试用例后自动生成覆盖率报告。(ncover)

XUnit.Net

XUnit.NET是一个开源的的单元测试工具,由NUnitv2的原始发明者编写,支持C#,F#,VB.NET版以及其他.NET语言,由.NET基金会支持,它采用了一种非常独特、现代和灵活的单元测试方法。

XUnit.NET强调编写具有较高的可读性,简单性的单元测试,与其它单元测试框架相比,有一些独特的地方:

XUnit比其他.Net单元测试框架更加灵活和可扩展,它允许创建新的属性来控制测试。XUnit支持两种类型的测试,[Fact】和【Theory】,[Fact】通常用来测试不需要参数的方法,并且在XUnit中,用【Skip】属性代替了[Ignore],并要求指定跳过该测试的原因;【Theory】支持数据驱动的测试,可以用[InlineData]属性实现参数的传递,并支持多次执行同一个方法,是XUnit可扩展性强的一个重要体现。

图2-5XUnit.NET带参测试方法实例

XUnit支持更好地进行隔离测试。与其它测试框架不同,在xUnit中,每个测试方法运行后都会进行实例化操作,执行后释放相应的空间,测试之间更加独立,可以以任何顺序执行测试,而不必担心一个测试对其他测试的影响,消除了不同测试方法之间的依赖性。

XUnit取消了【SetUp】和【TearDown]方法,而采用构造函数进行初始化,使用IDisposable进行测试类的后处理等操作,让每个测试对其需要的内容进行初始化。

支持为测试用例设置分类,执行时执行指定分类的测试方法:[Trait("Category","UI")];

支持为测试用例设置参数:[Theory][InilineData];

支持使用断言等方式,对返回异常的测试用例进行异常判断:Assert.Throws.Exception,长期使用[ExpectedException]会发现各种问题。首先,它没有具体说明应该在哪一行代码中引发异常,这会导致微妙且难以跟踪的失败,这些失败会在通过测试时显示出来。其次,由于处理不在测试的常规代码流程之内,因此它没有提供机会全面检查异常本身的详细信息。Assert.Throws允许您测试一组特定的代码以引发异常,并在成功期间返回异常,以便您可以针对异常实例本身编写进一步的断言。

图2-6XUnit.NET异常判断实例

支持通过注解等方式跳过执行带有该注解的测试用例,[Fact(Skip=“reason”)】

工具试用

本节采用一段简易货币转换计算器代码作为被测代码来试用三款工具,其测试用例基本可以涵盖日常单元测试所需的功能。在试用过程中,同时采用了Moq框架及dotCover覆盖率扫描工具。

被测代码——简易货币转换计算器,主要有两个接口:ICaculator和IMoneyEx,和一个ICaculator接口的实现类:Caculator。其功能是实现简单运算及货币汇率转换功能。

ICaculator接口定义如下:

publicinterfaceICalculator

{

intAdd(intparam1,intparam2);

intSubtract(intparam1,intparam2);

intMultipy(intparam1,intparam2);

doubleDivide(intparam1,intparam2);

intConvertUSDtoRMB(intunit);

}

IMoneyEx接口定义如下:

publicinterfaceIMoneyEx

intGetActualUSDValue();

ICaculator接口的实现类Caculator如下:

publicclassCalculator:ICalculator

privateIMoneyEx_feed;

publicCalculator(IMoneyExfeed)

this._feed=feed;

#regionICalculatorMembers

publicintAdd(intparam1,intparam2)

returnparam1+param2;

publicintSubtract(intparam1,intparam2)

returnparam1-param2;

publicintMultipy(intparam1,intparam2)

returnparam1*param2;

publicdoubleDivide(intparam1,intparam2)

returnparam1/param2;

publicintConvertUSDtoRMB(intunit)

returnunit*this._feed.GetActualUSDValue();

#endregion

测试代码

Mock代码

//定义mock逻辑

privateIMoneyExPrvGetMockExchangeRateFeed()

MockmockObject=newMock();

mockObject.Setup(m=>m.GetActualUSDValue()).Returns(500);

returnmockObject.Object;

不同测试工具测试代码

(1)MsTest

namespaceCalculatorPkg.Tests

privatestaticICalculatorcalculator=null;

[TestClass()]

publicclassMsTestCal

//初始化

[TestInitialize]

publicvoidSetup()

IMoneyExfeed=this.PrvGetMockExchangeRateFeed();

calculator=newCalculator(feed);

Console.WriteLine("beforetest...");

//带参测试方法,并对测试方法分类

[TestMethod()]

[DataRow(1,1)]

[TestCategory("cal")]

publicvoidTC1_Add(inta,intb)

intc=a+b;

Assert.AreEqual(c,calculator.Add(a,b));

//忽略测试用例

[Ignore]

publicvoidTC1_Divide9By3()

doubleactualResult=calculator.Divide(9,3);

intexpectedResult=3;

Assert.AreEqual(expectedResult,actualResult);

//异常判断

[ExpectedException(typeof(DivideByZeroException))]

publicvoidTC2_DivideByZero()

doubleactualResult=calculator.Divide(9,0);

//使用mock类

[TestCategory("convert")]

publicvoidTC3_ConvertUSDtoRMBTest()

intactualResult=calculator.ConvertUSDtoRMB(1);

intexpectedResult=500;

//后处理

[TestCleanup]

publicvoidCleanup()

Console.WriteLine("aftertest...");

DotCover结果显示:

(2)Nunit

//添加TestFixture标识类是测试类

[TestFixture]

publicclassNUnitTest

[SetUp]

//测试用例分类,跳过测试方法

[Test(Description="Add1with1.Expectedresultis2.")]

[Category("add")]

[Ignore("Methodisignored")]

publicvoidTC0_Add1With1()

intactualResult=calculator.Add(1,1);

intexpectedResult=2;

//带参测试方法

[Test()]

[Category("sub")]

[TestCase(0,1)]

[TestCase(1,1)]

[TestCase(2,1)]

publicvoidTC0_SUB(inta,intb)

intactualResult=calculator.Subtract(a,b);

intexpectedResult=a-b;

//测试divide方法,以及测试用例排序

[Test(Description="Divide9by3.Expectedresultis3.")]

[Category("divide")]

[Order(2)]

Console.WriteLine("TC1_Divide9By3:"+DateTime.Now.TimeOfDay.ToString());

[Test(Description="Divideanynumberbyzero.ShouldthrowanSystem.DivideByZeroExceptionexception.")]

[Order(3)]

Console.WriteLine("TC2_DivideByZero:"+DateTime.Now.TimeOfDay.ToString());

Assert.That(()=>calculator.Divide(9,0),Throws.TypeOf());

//mock示例

[Test(Description="Convert1USDtoRMB.Expectedresultis500.")]

[Category("convert")]

[Order(1)]

[TearDown]

publicvoidTeardown()

执行顺序结果:

图NUnit测试用例执行顺序验证

即执行情况符合规定的顺序。

(3)XUnit.NET

publicclassXUnitCal

[Fact(Skip="Methodisignored")]

[Trait("Category","add")]

ICalculatorcalculator=newCalculator(feed);

Assert.Equal(expectedResult,actualResult);

[Theory()]

[Trait("Category","multi")]

[InlineData(0,1)]

[InlineData(1,1)]

publicvoidTC0_multi(inta,intb)

intactualResult=calculator.Multipy(a,b);

intexpectedResult=a*b;

[Fact()]

[Trait("Category","divide")]

//doubleactualResult=calculator.Divide(9,0);

Assert.Throws(()=>calculator.Divide(9,0));

[Trait("Category","convert")]

工具对比

本次调研重点研究的三款C#单元测试工具(MsTest、NUnit、XUnit·NET)来说,使用区别度并不是很大,具体如下:

MsTest作为内置的visualstudio测试工具来讲,操作简单,易于使用;另外,如果已经使用visualstudio作为编译器,不用做任何的安装即可使用,也是其较为明显的优点之一。但是其也存在在带参测试时不能同时支持异常判断,以及无法对测试用例排序等缺点。

NUnit作为比较成熟的C#单元测试工具,好处包括可以按名称空间进行测试分组,添加测试用例注释(使用相同的参数多次运行相同的测试)及对测试用例排序等功能,并且它与Opencover和ReportGenerator进行覆盖分析的效果很好。主要的缺点是它没有像MSTest那样集成,但是通过Nuget现在在visualstudio中使用NUnit已经成为一件比较容易的事情。NUnit还有一个不同于其它测试工具的特点是NUnit2中有自己的GUI,可以不通过VS单元来看测试结果,但是如上所说,GUI只在NUnit2中提供,而现在普遍使用的都是NUnit3。

XUnit.NET作为NUnit的进阶简化版,是一种和NUnit极其相似的简单现代的单元测试框架。XUnit.NET不同于其它测试工具的特点主要有两个:一是取消了单元测试框架中的前后处理方法,为每个测试方法都创建测试类的新实例,即提高了测试用例之间的隔离性;二是用断言替代了属性的方式来捕捉异常,不采用Attribute的方式来捕捉异常有两方面的好处:在代码中直接断言(Assert)能捕捉到更多种类的异常;遵守Arrange-Act-Assert(or“3A”)模式:即测试命名上“范围-作用-断言”规范。但是正是由于其简化的特性,其缺点也显而易见,即一些高阶的测试可能无法用XUnit完成,并且和NUnit一样,XUnit与VS的集成没有MsTest那么自然。

总结

本次调研重点测评了三款C#开源单元测试工具,对其特性及基本使用进行了介绍。其实在开源社区蓬勃发展的今天,众多开源工具之间的区别也通过很多次迭代渐渐在缩小,如本次重点调研的三款工具虽各有优势和劣势,但是差异已经不再那么明显,大家在使用时结合自身的业务背景来选择合适的工具即可。

【重点来了】!!请不要忘记时刻学习着~~这点我相信大家应该都能理解,所以不用写什么:除非你是五年、十年工作经验的测试人员,仅此一点“不学习就会落后”!

现在我邀请你进入我们的软件测试学习交流群,备注“入群”,大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,还会有免费直播课,收获更多测试技巧,我们一起进阶Python自动化测试/测试开发,走向高薪之路。

THE END
1.3款C#开源且实用的工具类库,工作效率提升利器!c#工具类库在日常工作开发中工具类库是软件开发中不可或缺的一部分,它们通过提供代码重用、通用功能、隐藏复杂性、提高代码质量、扩展性等方面的优势,帮助开发者更高效、更稳定地构建软件应用程序。今天大姚给大家分享3款C#开源且实用的工具类库,希望能帮助到有需要的小伙伴。 https://blog.csdn.net/qq_37237487/article/details/140281009
2.C#开发的基础工具类集合开源研究系列文章今天发布一个基础工具类代码集合。 以前有发布过一个类似的类库(见博文: Magical平台类库代码分享 ),不过那个版本有点久了,也没有这次这个全面,这次发布的是一个很多地方用到的基础类库代码。 1、 项目目录; 项目底下就是DLL类库的代码: 2、 函数介绍; 举例一个类https://www.cnblogs.com/lzhdim/p/17690132.html
3.C#开发的开源内网穿透工具NSmartProxyNSmartProxy是一款免费的内网穿透工具。 使用中如果有任何问题和建议,可以点击这里加入Gitter群组或者点击这里加入QQ群 (群号:813170640)我们一起讨论。 https://github.com/tmoonlight/NSmartProxy?tab=readme-ov-file 附件:NSmartProxy-master.zip 目录 http://lifong.app66.cn/mis/bbs/showbbs.asp?id=24556
4..NET开发工具开源软件OSCHINAOSCHINA.NET 是目前领先的中文开源技术社区。我们传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台https://www.oschina.net/project/tag/116/dotnet-development-t
5.开源:C#代码自动生成工具,支持站点前后台【实例简介】开源:C# 代码自动生成工具,支持站点前后台 【实例截图】 【核心代码】.└── WebAutoCodeOnline-master ├── CleanSolution.bat ├── Common │ ├── Common.csproj │ ├── Encrypt │ │ ├── AESHelper.cs │ │ ├── EncodingHelper.cs │ │ ├── EncryptHelper.cs │ https://www.haolizi.net/example/view_259340.html
6.Core3.1.Net5框架的C#WinForm开源控件库工具类库SunnyUI.Net, 是基于.Net Framework 4.0+、.Net 5、.Net 6 框架的 C# WinForm 开源控件库、工具类库、扩展类库、多页面开发框架。 源码编译环境: VS2022,V3.0.9增加了.Net6的支持,所以编译需要VS2022。 安装.NetFramework4.0目标包的方法见:https://www.cnblogs.com/yhuse/p/15536393.html https://toscode.mulanos.cn/WeiAi999/SunnyUI
7.收集GitHub上有关C#/.Net.NetCore有趣有用热门的开源224、一个C#开源工具库,集成了超过1000个扩展方法(Z.ExtensionMethods):为.NET开发人员提供一系列实用的扩展方法,可以减少重复劳动、提高开发效率,支持.NET Framework 和 .NET Core。 Github:https://github.com/zzzprojects/Z.ExtensionMethods 详细介绍:点击查看 223、StableSwarmUI:StableDiffusion客户端,官方出品、https://github.com/bianchenglequ/NetCodeTop
8..NetCore微服务为什么用C# C# 容易学, 容易掌握,而且最重要的是易于大型工程师团队协作开发、维护。使用高效并发、扩展的标准库和稳步改进的运行时, 它实际上是编写 microservices0 Xamarin介绍 0 0 微服务开发的12项要素 0 0 .NET Standard@Xamarin.Forms 0 0 自动化流程开源框架BotSharp 0 0 更多http://www.csharpkit.com/
9.c#编译软件c#编程工具c#代码生成器c#编译器有哪些c#是编程开发最常用的语言之一,它是一种安全的、稳定的、简单的、优雅的编程语言,c#代码工具则是由c#相关的软件组成,它们多用于软件的编程开发,代码生成,代码加密等等,涵盖了很多的范围,都是为了给用户提供方便。 在本页面,为大家带来的,就是关于c#的许多相关的软件,相信不管是在c#语言的编程开发还是学习上,都能https://m.qqtn.com/k/cdmgj
10.分享C#常用开源类库收集灵雨飘零SharpMap是一款易于使用的地图渲染器,它可以为Web和Windows应用程序渲染GIS数据。SharpMap是使用C#编写,基于.NET 2.0框架上开发的开源项目。 monoGIS monoGIS将成为Mono平台下的开源完整GIS。已经发布了internet mapserver,OGC WMS实现和一些工具像空间格式转换。 https://www.iteye.com/blog/2329939
11.[开源]简洁实用精美C#WinForm开源控件库,较全面的UI图形界面库SunnyUI.Net, 是基于.Net Framework 4.0+、.Net 5、.Net 6 框架的 C# WinForm 开源控件库、工具类库、扩展类库、多页面开发框架。 二、界面展示 1、开源控件库 基于.Net Framework4.0,原生控件开发,参考 Element主题风格,包含 按钮、编辑框、下拉框、数据表格、工控仪表、统计图表在内的常用控件超过 70 个,满足https://code.exmay.com/detail/1127
12.有哪些好用的c#代码编辑器–PingCodeAtom:Atom是由GitHub开发的开源代码编辑器,可通过插件集成C#开发工具。它具有友好的用户界面、内置包管理器和丰富的主题和插件选择,可以根据个人喜好进行定制。 Notepad++:Notepad++是一款免费的Windows文本编辑器,支持多种编程语言,包括C#。尽管功能相对较简单,但它易于使用,适合进行简单的C#编码和脚本处理任务。 https://docs.pingcode.com/ask/323634.html
13.(二)开源C#Winform控件库《SunnyUI》强力推荐开源许可协议:GPL-3.0 项目地址:https://gitee.com/yhuse/SunnyUI 项目简介 SunnyUI是一套开源的C# Winform控件库、工具类库、扩展类库、多页面开发框架。 http://SunnyUI.Net 是控件库作者申请的域名,但还未部署,作者将会在该网站发布控件库技术分享文章,大家敬请期待吧。 https://cloud.tencent.com/developer/article/1766158
14.在线运行C#这是一个简单方便的C#在线运行工具,支持在线编译、在线调试和在线结果的实时反馈。https://www.bejson.com/runcode/csharp
15.这两个强大的开源C#反编译逆向工具,探索C#桌面应用的秘密这个两个强大的工具外,还有其他的反编译工具,如JetBrains dotPeek、Telerik JustDecompile、.NET Reflector等。一般的程序,我们可以通过这些工具来探索、学习。但是安全意识比较强的产品,会通过混淆加密等方式来加固自己的应用,使难度增加。 C#的应用也比较多,有时候,我们想要研究一下别人的优秀的项目,可能会借助一些非常https://www.51cto.com/article/750622.html
16.Blazor使用C#生成客户端Web应用.NET在macOS、Windows 或 Linux 上进行开发,以生成跨平台网站和服务。安装 C# 开发工具包以获得最佳体验。 下载VS Code Visual Studio 使用适用于 Windows 上的 .NET 的最佳 IDE 进行开发。打包了一系列工具和功能,可用于提升和增强软件开发的每个阶段。 下载Visual Studio https://dotnet.microsoft.com/zh-cn/apps/aspnet/web-apps/blazor
17.C#常用开源框架收集该项目使用纯 C# 开发,易于扩展和集成到已有的项目。只要你的已有系统是使用.NET开发的,你都能够使用 SuperSocket来轻易的开发出你需要的Socket应用程序来集成到你的现有系统之中。 SuperWebSocket http://superwebsocket.codeplex.com/ SuperWebSocket是基于.NET开源Socket框架SuperSocket开发的, SuperSocket所支持的大部分https://www.jianshu.com/p/efadbc5ee3d1