单元测试
Posted .NET开发菜鸟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单元测试相关的知识,希望对你有一定的参考价值。
一、什么是单元测试
单元测试就是编写一段代码,用来检查某个特定条件下,另外一段代码的行为是否符合我们的预期。
单元测试的代码与实际程序的代码具有同等的重要性。
每一个单元测试,都是用来定向测试它所对应的一个单元的代码是否正确执行(一般只的是对方法的测试)。
单元测试应该由被测试代码的编写者来完成(即程序员自己来完成,因为只有程序员自己才知道程序的效果)。
二、单元测试的好处
能够协助程序员尽快找到代码中bug的具体位置。
能够让程序员对自己的程序更有自信。
能够让程序员在提交项目之前就将代码变得更加的强壮。
能够协助程序员更好的进行开发。
能够向其他的程序员展示你写的程序该如何调用。
能够让项目主管更了解系统当前的情况。
三、编写单元测试
VSTS中的测试工具可以对任何类、接口、结构等实体中的字段、属性、构造函数、方法等进行单元测试。用的最多的是对方法进行测试。
单元测试分为两种:
1、整体测试。
2、单独测试。
通常在解决方案中添加一个测试项目,用于单元测试。将单元测试代码和业务代码分开。
1、新建一个空白的解决方案,命名为:UnitTestingSolution
2、新建一个控制台应用程序,作为业务代码进行测试
3、在控制台应用程序中新建一个Triangle类,对Triangle类里面的方法进行测试,Triangle类定义如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace UnitTestingCon 8 { 9 /// <summary> 10 /// 三角形 11 /// </summary> 12 public class Triangle 13 { 14 // 定义三角形三边长的属性 15 public float SideLength1 { get; private set; } 16 public float SideLength2 { get; private set; } 17 public float SideLength3 { get; private set; } 18 19 /// <summary> 20 /// 构造函数,用来给属性赋值 21 /// </summary> 22 /// <param name="sideLength1"></param> 23 /// <param name="sideLength2"></param> 24 /// <param name="sideLength3"></param> 25 public Triangle(float sideLength1, float sideLength2, float sideLength3) 26 { 27 SideLength1 = sideLength1; 28 SideLength2 = sideLength2; 29 SideLength3 = SideLength3; 30 } 31 32 /// <summary> 33 /// 判断是否是一个三角形 34 /// 1、每条边都是正数 35 /// 2、两边之和大于第三边 36 /// </summary> 37 /// <returns></returns> 38 public bool IsTriangle() 39 { 40 // 三边长度有不是正数的返回false 41 if((SideLength1<=0)|| (SideLength2 <= 0)|| (SideLength3 <= 0)) 42 { 43 return false; 44 } 45 else 46 { 47 return (((SideLength1+SideLength2)>SideLength3) 48 &&((SideLength1+SideLength3))>SideLength2 49 &&((SideLength2+SideLength3)>SideLength1)); 50 } 51 } 52 53 /// <summary> 54 /// 判断是否为等边三角形 55 /// 1、必须是三角形 56 /// 2、三条边必须都相等 57 /// </summary> 58 /// <returns></returns> 59 public bool IsEquilateralTriangle() 60 { 61 if(!IsTriangle()) 62 { 63 return false; 64 } 65 else 66 { 67 return ((SideLength1==SideLength2)&&(SideLength1==SideLength3)&&(SideLength2==SideLength3)); 68 } 69 } 70 71 /// <summary> 72 /// 获取三角形的面积 73 /// 1、如果不是三角形,面积为0 74 /// 2、如果s为三角形的三边(a、b、c)和的一半 75 /// 三角形的面积为(s*(s-a)*(s-b)*(s-c))的平方根 76 /// </summary> 77 /// <returns></returns> 78 public double GetArea() 79 { 80 if(!IsTriangle()) 81 { 82 return 0; 83 } 84 else 85 { 86 float s = (SideLength1 + SideLength2 + SideLength3) * 0.5f; 87 return Math.Sqrt(s * (s - SideLength1) * (s - SideLength2) * (s - SideLength3)); 88 } 89 } 90 } 91 }
4、新建单元测试项目
在解决方案上面右键,选择“添加”->新建项目:
在打开的对话框中选择测试下面的单元测试项目,项目名称:要测试的类名+Test
创建的单元测试项目结构如下:
UnitTest1是默认生成的测试类,可以删掉。
5、新建测试类
在单元测试项目上右键,选择“添加”->“类”,然后选择测试下面的单元测试
约定:要测试的类和测试的方法以Test结尾。
单元测试默认在Microsoft.VisualStudio.TestTools.UnitTesting命名空间下面。
6、编写测试代码
编写测试代码前首先要添加对测试项目的引用,要测试哪个项目就要添加对哪个项目的引用。测试方法上面要添加特性[TestMethod],表示是一个测试方法。添加是否是三角形方法的测试代码,测试代码如下:
/// <summary> /// 测试是否是三角形这个方法 /// </summary> [TestMethod] public void IsTriangleTest() { #region 测试用例一 // 初始化属性 float SideLength1 = 0f; float SideLength2 = 0f; float SideLength3 = 0f; // 实例化 riangle target = new Triangle(SideLength1, SideLength2, SideLength3); // 定义一个变量,保存期待的结果 bool excepted = false; // 定义一个变量,保存实际的结果 bool actual; actual = target.IsTriangle(); // 断言期待的结果和实际的结果是否相等,如果相等表示测试通过,否则测试失败 Assert.AreEqual(excepted, actual); #endregion }
7、运行测试代码
在运行测试代码以前,需要打开测试资源管理器窗口和代码覆盖率结果窗口,在菜单栏的测试里面打开
运行测试代码,可以在测试方法上面右键选择运行测试:
或者选择菜单栏测试里面的运行:
或者是在测试资源管理器里面的测试方法上面直接右键:
运行测试代码,查看测试结果:
表示测试通过。
注意:在测试方法里面添加断点,可以进行调试,可以按照上面的三种方式选择调试测试。
查看代码覆盖率:
从上面的截图中可以看出,代码覆盖率只要25%,说明测试代码写的还不够全面。需要继续完善单元测试的代码。
8、Assert类
Assert:断言
在Microsoft.VisualStudio.TestTools.UnitTesting命名空间中。
Assert类是一个静态类。
序号 | 方法 | 描述 |
1 | AreEqual | 判断两个值是否相等,如果两个值不相等,则测试失败。有多个重载 |
2 | AreNotEqual | 判断两个值是否不相等,如果两个值相等,则测试失败。有多个重载 |
3 | AreSame | 判断引用的对象是否相同。如果两个输入内容引用不相同的对象,则测试失败。 |
4 | AreNotSame | 判断引用的对象是否不相同。如果两个输入内容引用相同的对象,则测试失败。 |
5 | Fail | 断言失败 |
6 | Inconclusive | 表示无法证明为true或false的测试结果 |
7 | IsFalse | 指定的条件是否为false。如果该条件为true,则测试失败。 |
8 | IsTrue | 指定的条件是否为true。如果该条件为false,则测试失败。 |
9 | IsInstanceofType | 测试指定的对象是否为所需类型的实例。如果所需的实例不在该对象的继承层次结构中,则测试失败。 |
10 | IsNotInstanceOfType | 测试指定的对象是否为所需类型的实例。如果所需的实例在该对象的继承层次结构中,则测试失败。 |
11 | IsNull | 测试指定的对象是否为空。 |
12 | IsNotNull | 测试指定的对象是否为非空。 |
9、单元测试中的特性
9.1 TestClass特性
用于标识类是一个测试类。
用法:在类上面标注[TestClass]
测试类的命名方式:<被测试类的类名>Test
TestMethod特性
用于标识一个测试方法。
用法:在测试方法上面标注[TestMethod]
测试方法的命名方式:<被测试方法的方法名>Test
注意:在测试方法上面一定要添加TestMethod特性,否则该方法不会被执行。
10、代码覆盖率
代码覆盖率是单元测试写的是否合理或是否达到要求的一个唯一的标准。
代码覆盖率是测试代码所运行到的实际程序路径的覆盖率。
四、单元测试的标准
1、哪些代码需要单元测试
a、既有代码添加单元测试的步骤
第一步:对所有程序集中的公开类以及公开类里面的公开方法添加单元测试。
第二步:对于构造函数和公共属性进行单元测试。
第三步:添加全面单元测试。
b、给哪些代码添加单元测试
针对属于框架技术中的代码添加单元测试。
为业务逻辑层对界面公开的方法添加单元测试。
c、对应刚开始的项目,应该对所有公开的方法和属性都添加单元测试。
2、单元测试代码的写法
a、编写单元测试代码时注意事项
所测试的方法的代码覆盖率必须达到100%。
所测试的代码内部的状态。
被测试的代码所使用的外部设备的状态。(比如打印机的状态)
b、怎么提高代码覆盖率
边界条件数据。
空数据。
格式不正确数据。
3、单元测试是否达到预期值
代码覆盖率100%并不能完全保证代码正确。
需要对执行的结果进行断言。
平均每5行测试代码要有一个断言。
测试外部设备状态更改时,测试是否正常通过。
以上是关于单元测试的主要内容,如果未能解决你的问题,请参考以下文章