注:本文示例环境数组
VS2017
XUnit 2.2.0 单元测试框架
xunit.runner.visualstudio 2.2.0 测试运行工具
Moq 4.7.10 模拟框架网络
确保软件应用程序按做者的指望执行操做,其中最好的一种方法是拥有自动化测试套件。 能够对软件应用程序进行各类不一样的测试,包括集成测试、Web 测试、负载测试等。 测试各个软件组件或方法的单元测试是最低级测试。框架
所谓单元测试(unit testing),就是开发者编写的一小段代码,用于对软件中的最小单元进行检查和验证,其通常验证对象是一个函数或者一个类。一般而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。编辑器
对于我我的来讲,主要是防止本身犯低级错误的,同时也方便修改(BUG修复)而不引入新的问题。能够放心大胆的重构。简言之,这个简单有效的技术就是为了令代码变得更加完美。ide
能够概括为如下几个理由。函数
对单元测试存在的误解,如:单元测试属于测试工做,应该由测试人员来完成,因此单元测试不属于开发人员的职责范围。工具
答:虽然单元测试虽然叫作"测试",但实际属于开发范畴,应该由开发人员来作,而开发人员也能从中受益。单元测试
没有真正意识到单元测试的收益,认为写单元测试太费时,不值得。测试
答:在开发时越早发现bug,就能节省更多的时间,下降更多的风险。单元测试先期要编写测试用例,是须要多耗费些时间,可是后面的调试、自测,均可以经过单元测试处理,不用手工一遍又一遍处理。实际上总时间被减小了。spa
项目经理或技术主管没有要求写单元测试,因此不用写。
答:写单元测试应该成为开发人员的一种本能,开发自己就应该包含单元测试。
不知道有单元测试这回事,不知道如何用。通过这篇文档的说明,就基本知道如何处理单元测试。
经常使用单元测试框架:MSTest (Visual Studio官方)、XUnit 和 NUnit。
(如下主要讲解MSTest 和NUnit的使用,XUnit操做和NUnit操做基本相似)
新建一个Solution,并添加项目UnitTestDemo(用于编写被测试的项目)
在该工程中添加UnitTestClass类,并书写一个静态的GetTriangle(string[] sideArr) 函数用来返回一个三角形的类型。
namespace UnitTest { public class UnitTestClass { /// <summary> /// 获取三角形类型. /// </summary> /// <param name="sideArr">三角形三边长度数组.</param> /// <returns>返回三角形类型名称.</returns> public static string GetTriangle(string[] sideArr) { string result = string.Empty; int a = int.Parse(sideArr[0]); int b = int.Parse(sideArr[1]); int c = int.Parse(sideArr[2]); if (a + b > c && a + c > b && b + c > a) { if (a == b && a == c) { result = "等边三角形"; } if (a == b || a == c || b == c) { result = "等腰三角形"; } else { result = "通常三角形"; } } else { result = "不构成三角形"; } return result; } } }
新建好测试项目以后,你会获得一个UnitTest1测试类模板,即一个带有[TestClass] attribute标记的类和一个带有[TestMethod] attribute标记的空方法public void TestMethod1()。
单元测试项目没法自动访问它正在测试的类库。 能够经过添加对类库项目的引用来提供测试库访问权限。 为此,请右键单击UnitTestProject1项目,而后依次选择“添加” > “引用”。在“引用管理器”对话框中,而后选择 UnitTestDemo项目,以下图中所示。
在UnitTestDemoTests项目中添加UnitTestDemo项目的引用,如今咱们的solution就具备了下图所示的目录结构。
5. 在UnitTestDemoTests项目中的UnitTest1类中,将模板提供的样本单元测试代码替换为如下代码:
using UnitTest; using System; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace UnitTestDemoTests { [TestClass] public class UnitTest1 { [TestMethod()] public void GetTriangle_Test() { string[] sideArr = {"5", "5", "5"}; Assert.AreEqual("等边三角形", UnitTestClass.GetTriangle(sideArr)); } } }
6. 生成UnitTestDemoTests测试项目,在生成项目后,测试项将出如今测试资源管理器中。 若是测试资源管理器窗口不可见,请选择顶级 Visual Studio 菜单上的“测试”,而后依次选择“窗口(Windows)”、“测试资源管理器(Ctrl + E,T9)”,如图所示。
7. 在测试资源管理器上能够看到刚刚所写的测试方法,这样在GetTriangle_Test单击右键选择“运行所选定的测试”就能够在Test Explorer里看到单元测试的运行结果,以下图所示。
能够看到,咱们在单元测试中提供的例子的指望是输出“等边三角形”,运行结果倒是“等腰三角形”。再看一看 GetTriangle() 函数的代码,原来是在对在判断三边数值是等边三角形以后没有使用 else if 又用 if 判断为等腰三角形了。经过这个简单的单元测试就可以发现一些意向不到的错误。不要觉得这里的bug很低级,相似的状况确实会在现实中发生。
8. 把上面的错误更正后,再次运行TestMethod1()就会获得测试已经过的结果,如图所示。
建立单元测试项目和测试方法,除了以上经过手动建立单元测试项目和根据你的要求进行编写测试用例以外,还能够从你的项目的方法上直接生成单元测试项目和单元测试存根,那样操做更加方便,速度也会更快一些。
这里涉及测试框架的选择,MSTest是VS自带的测试框架。新的MS TEST如今是经过Nuget的包发布了,目前MS发布了两个版本:
- MS TEST V1:V1的版本依赖于一个包: MSTest.TestFramework
- MS TEST V2:V2的版本依赖于两个包: MSTest.TestFramework 和 MSTest.TestAdapter
这两个版本使用起来仍是大同小异的,MSTest v2 主要是为了.net core准备的,固然也能够在.net framework上运行,而且在v1上新加入了一些扩展。
你使用的单元测试框架和 Visual Studio IntelliSense 将指导你完成为代码项目的单元测试编写代码。 若要在测试资源管理器中运行,大多数框架要求你添加特定的属性来识别单元测试方法。 框架还提供了一种方法,一般经过断言语句或方法属性,来指示测试方法是否已经过或失败。 其余属性标识可选的安装方法,即在类初始化时和每一个测试方法和每一个拆卸方法以前的安装方法,这些拆卸方法在每一个测试方法以后和类被销毁以前运行。
AAA(准备、执行、断言)模式是编写待测试方法的单元测试的经常使用方法:
[TestMethod()] public void GetTriangle_Test() { // arrange string[] sideArr = { "5", "5", "5" }; // 准备传给待测试方法的数据 string expected = "等边三角形"; // act var actual = UnitTestClass.GetTriangle(sideArr); // 调用测试方法 // assert Assert.AreEqual(expected, actual); // 验证待测试方法的执行结果是否与预期相同 }
在某些状况下(例如经过网络获取数据),经常不但愿程序卡住而占用太多时间,经过设置测试方法的超时时间,来测试一个方法是否在预期时间内执行。
[TestMethod()] [Timeout(2000)] // 毫秒 要在单个测试方法上设置超时时间 public void GetTriangle_Test() { ... }
[TestMethod()] [Timeout(TestTimeout.Infinite)] // 毫秒 将超时时间设置为容许的最大值 public void GetTriangle_Test() { ... }
什么是参数化测试?
答:简单的说,就是一样的逻辑,根据输入参数不一样,给出不一样的结果。由于只是参数不一样,因此并不但愿把测试方法写多遍,可是又但愿对每一个参数的测试成为一个独立的测试用例。举例说,假定我有一个数学计算的方法是把两个整数相加求和,我但愿证实这个方法对于任意两个数都是经过的。
在MSTest中能够经过DataRow Attribute 来指定测试用例的参数,实现参数化测试:
/// <summary> /// 相加(待测试方法) /// </summary> /// <param name="num1">数值1</param> /// <param name="num2">数值2</param> /// <returns>计算结果</returns> public static int Add(int num1, int num2) { return Math.Abs(num1 + num2); }
/// <summary> /// 测试方法 /// </summary> [TestMethod()] [DataRow(10, 20)] [DataRow(-2, -5)] [DataRow(1, -2)] [DataRow(5, null)] public void Add_Test(int num1, int num2) { Assert.AreEqual(UnitTestClass.Add(num1, num2), num1 + num2); }
测试了全部可能的状况,以达到更好的覆盖率。上方给出示例Add方法的单元测试运行测试结果以下图所示。
测试结果:测试结果指出对两个数相加操做的方法,目标方法还取了绝对值,与相应结果不符。
可使用测试资源管理器为你的测试启动调试会话。 使用 Visual Studio 调试程序能够无缝地逐句得使你在单元测试和所测试项目之间来回反复。 若要开始调试:
在 Visual Studio 编辑器中,在想要调试的一个或多个测试方法中设置断点。
在测试资源管理器中,选择测试方法,而后点击右键从快捷菜单选择“调试选定的测试”。
3. 进入调试模式
F5 继续。
F10 执行下一行代码,但不执行任何函数调用。
F11 在执行进入函数调用后,逐条语句执行代码。
Shift + F11 执行当前执行点所处函数的剩余行。
Shift + F5 中止运行程序中的当前应用程序。可用于“中断”模式和“运行”模式。
1)下载安装NUnit插件
咱们在VS中选择工具菜单栏下的扩展和更新,选择联机并在搜索框中输入NUnit。有2个版本的Nunit适配器,分别为NUnit 3.x(最新版为3.4.1)和NUnit 2.x(最新版为2.6.4),都支持Visual Studio 2012+。若想在VS2010中集成,须要安装NUnit 2.6.4安装包(可在官网下载)与VS2010 NUnit整合插件下载,下载安装完毕就能在 VS2010 的视图=>其余窗口中看到 Visual Nunit (或使用快捷键Ctrl + F7),打开该视图,将之拖到合适的位置。
2)建立NUnit单元测试项目
未完待续..
7. 中止实时单元测试:
IntelliTest 浏览你的 .NET 代码,以生成测试数据和单元测试套件。 对于代码中的每一个语句,将生成执行该语句的测试输入。 为代码中的每一个条件分支执行案例分析。 例如,分析 if 语句、断言和可能引起异常的全部操做。 此分析用于为你的每一个方法生成参数化单元测试的测试数据,从而建立具备较高代码覆盖率的单元测试。
当你运行 IntelliTest 时,你可轻松看到哪些测试会失败,并可添加任何须要的代码来修复它们。 你可选择要保存到测试项目中的已生成测试,以提供回归套件。 当你更改代码时,从新运行 IntelliTest,以使生成的测试与你的代码更改同步。
IntelliTest 仅可用于 C# 且不支持 x64 配置。
若要生成单元测试,你的类型必须是公共类。 不然,先建立单元测试,而后再生成它们。
在 Visual Studio 中打开解决方案。 而后打开包含你要测试的方法的类文件。
在代码中右键单击一种方法并选择“建立 IntelliTest”,为方法中的代码建立生成单元测试项目。
接受默认格式以生成测试,或更改项目和测试的命名方式。 你能够建立新的测试项目或将你的测试保存到现有项目。
3. 建立测试项目成功以后,选择上图中“运行 IntelliTest”,为方法中的代码运行IntelliTest单元测试项目。
IntelliTest 使用不一样的输入屡次运行你的代码。 每次运行都会在表中表示出来,显示输入测试数据以及产生的输出或异常。
要为一个类中的全部公共方法生成单元测试,只需右键单击类而不是特定的方法。 而后选择“运行 IntelliTest”。 使用“浏览结果”窗口中的下拉列表,显示类中每一个方法的单元测试和输入数据。
对于经过的测试,检查结果列中报告的结果是否与你对代码的预期要求匹配。 对于失败的测试,根据须要修复你的代码。 而后从新运行 IntelliTest 来验证修复。