干货丨这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.c&c++开源库编译指南2.1 编译工具 2.2 CMake版本 2.3 windows环境配置 2.3.1 vs2008安装 2.4 linux环境配置 第三章 库文件命名 3.1 引言 3.2 命名规范 3.3 命名规范的优势 第四章 开源库编译实践 修订记录 声明:本文章旨在为 C/C++ 开发者提供一份兼具指导性与实用性的开源库编译参考资料。本文章所呈现的所有内容均为原创整理与https://blog.csdn.net/binary0006/article/details/144086155
2.三款C#开源且实用的工具类库,工作效率提升利器!全龄段友好的C#/.NET万能工具库,不管你是菜鸟新手还是骨灰级玩家都能轻松上手,这个库包含一些常用的操作类,大都是静态类,加密解密,反射操作,树结构,文件探测,权重随机筛选算法,分布式短id,表达式树,linq扩展,文件压缩,多线程下载,硬件信息,字符串扩展方法,日期时间扩展操作,中国农历,大文件拷贝,图像裁剪,验证码,断https://www.51cto.com/article/792261.html
3.C#开发的基础工具类集合开源研究系列文章C#开发的基础工具类集合 - 开源研究系列文章 Posted on 2023-09-10 14:39 lzhdim 阅读(26827) 评论(0) 编辑 收藏 举报 今天发布一个基础工具类代码集合。 以前有发布过一个类似的类库(见博文: Magical平台类库代码分享),不过那个版本有点久了,也没有这次这个全面,这次发布的是一个很多地方用到的基础类库https://www.cnblogs.com/lzhdim/p/17690132.html
4.(二)开源C#Winform控件库《SunnyUI》强力推荐开源许可协议:GPL-3.0 项目地址:https://gitee.com/yhuse/SunnyUI 项目简介 SunnyUI是一套开源的C# Winform控件库、工具类库、扩展类库、多页面开发框架。 http://SunnyUI.Net 是控件库作者申请的域名,但还未部署,作者将会在该网站发布控件库技术分享文章,大家敬请期待吧。 https://cloud.tencent.com/developer/article/1766158
5.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
6.SunnyUI.Net,基于C#.NetWinForm开源控件库工具类库SunnyUI.Net, 基于 C# .Net WinForm 开源控件库、工具类库、扩展类库、多页面开发框架 - xiawei666/SunnyUIhttps://github.com/xiawei666/SunnyUI
7.[开源]简洁实用精美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
8.C#WPF开源UI控件库MaterialDesign介绍C#教程在官方的demo中, 基本上涵括了所有组件, 在演示程序中,GitHub提供下载,我也把部分组件写了出来, 如下示例: 控件:按钮,下拉框, 开关, 日期, 选择框, 文本框, 进度条 演示效果 到此这篇关于C# WPF开源UI控件库MaterialDesign的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。https://www.jb51.net/article/235945.htm
9.分享C#常用开源类库收集灵雨飘零Gentle.NET是一款开源的与关系数据库(RDBMS)无关的对象持久层框架,可以自动生成SQL和对象结构。它拥有一个SQL工厂用来创建自定义查询、DataView构建助手和卓越的性能和完善的文档。 Ubik Ubik是C# 2.0下的ORM持久层框架,当前是WinForms应用程序开发提供的.它支持OPath的子集而可以进行面向对象查询,且包含一个网络事件系https://www.iteye.com/blog/2329939
10.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
11..NetCore微服务为什么用C# C# 容易学, 容易掌握,而且最重要的是易于大型工程师团队协作开发、维护。使用高效并发、扩展的标准库和稳步改进的运行时, 它实际上是编写 microservices 的完美语言。 为什么使用 microservices架构? 几乎所有的当代软件工程都专注于提高产品的发布上市的时间。Microservices 是一种以服务为导向的体系结构模式的http://www.csharpkit.com/
12.一些小众冷门但却非常实用的.NET(Core)开源库推荐相信大家也看过其他博主推荐的.NET开源库,大家推荐的都各有千秋,那今天博主就推荐一下我自用的一些.NET开源库吧,数量不多,虽然有些点赞数并不高,但个人觉得都是好到爆的一些工具库。本文旨在收录一些小众冷门的开源库,像AutoMapper、Autofac、epplus、Hangfire之类的大众都知晓的库,这里就不收录了。 https://www.jianshu.com/p/9721a290290a
13.ASP.NETCore适用于.NET的开源Web框架使用C#、OpenAI 和 Azure 构建智能应用 什么是 ASP.NET Core? .NET 是一个开发人员平台,由工具、编程语言、库组成,用于构建许多不同类型的应用程序。 ASP.NET Core 通过专门用于生成 web 应用的工具和库扩展了.NET 开发人员平台。 更深入发掘: 什么是 ASP.NET Core? https://dotnet.microsoft.com/zh-cn/apps/aspnet