软件工程(2019)第二次作业
单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。
比如对函数
abs()
,我们可以编写出以下几个测试用例:
输入正数,比如
1
、1.2
、0.99
,期待返回值与输入相同;输入负数,比如
-1
、-1.2
、-0.99
,期待返回值与输入相反;输入
0
,期待返回0
;输入非数值类型,比如
None
、[]
、{}
,期待抛出TypeError
。把上面的测试用例放到一个测试模块里,就是一个完整的单元测试。
如果单元测试通过,说明我们测试的这个函数能够正常工作。如果单元测试不通过,要么函数有bug,要么测试条件输入不正确,总之,需要修复使单元测试能够通过。
单元测试通过后有什么意义呢?如果我们对
abs()
函数代码做了修改,只需要再跑一遍单元测试,如果通过,说明我们的修改不会对abs()
函数原有的行为造成影响,如果测试不通过,说明我们的修改与原有行为不一致,要么修改代码,要么修改测试。
这种以测试为驱动的开发模式最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的时候,可以极大程度地保证该模块行为仍然是正确的。
以上来自廖雪峰的官方网站
也可以看一下其他的定义:
Visual Studio 2017 社区版 +AxoCover插件
注:因为社区版不提供代码覆盖率的功能,使用VSMarket的AxoCover 插件进行了补全
插件下载地址如下:
https://github.com/axodox/AxoCover
https://marketplace.visualstudio.com/items?itemName=axodox1.AxoCover
或者直接在VS插件与扩展选项里搜索AxoCover下载重启即可
其他的选择:
和AxoCover一样,NCrunch也是一款提供代码覆盖率的插件
至于使用哪个可以自行决定,使用说明请看官方文档
吐槽:本来找了一个叫OpenCover的插件,但是官方支持只适用到VS2015,VS2015的小伙伴可以用这个。
它的github和VS marketplace如下:
参考文章1:https://www.cnblogs.com/SivilTaram/p/vs_opencover_unit_coverage.html
虽然插件不同,但是基本步骤是一样的
2. 练习自动单元测试技术
参考文章:
1.创建C#的类库(Class Library)
文件->新建->项目
2.在创建的C#文件里编写代码
如图所示:
代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace ClassLibrary1 8 { 9 public class User 10 11 { 12 public User(string userEmail) 13 14 { 15 m_email = userEmail; 16 } 17 18 private string m_email; //user email as user id 19 20 } 21 }
3.创建单元测试:
右键选中User创建单元测试。
可以看到资源管理器生成了如下所示的项目:
4.修改单元测试UserTests.cs里的代码:
代码如下:
1 using Microsoft.VisualStudio.TestTools.UnitTesting; 2 using ClassLibrary1; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace ClassLibrary1.Tests 10 { 11 [TestClass()] 12 public class UserTests 13 { 14 [TestMethod()] 15 public void UserTest() 16 { 17 string userEmail = "someone@somewhere.com"; 18 19 User target = new User(userEmail); 20 21 Assert.IsTrue(target != null); 22 } 23 24 } 25 26 }
5.运行单元测试,测试结果如下
可以看到测试通过以及100%的代码覆盖率
导出测试报告如下所示:
当然这样的测试远远不够,考虑周全,我们还需要增加一些测试方法
6.增加测试方法
完整代码如下所示,在第4步的基础上增加了3个方法:
1 using Microsoft.VisualStudio.TestTools.UnitTesting; 2 using ClassLibrary1; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace ClassLibrary1.Tests 10 { 11 [TestClass()] 12 public class UserTests 13 { 14 [TestMethod()]//方法1 15 public void UserTest() 16 { 17 string userEmail = "someone@somewhere.com"; 18 19 User target = new User(userEmail); 20 21 Assert.IsTrue(target != null); 22 } 23 24 [TestMethod()]//方法2 25 [ExpectedException(typeof(ArgumentNullException))] 26 public void ConstructorTestNull() 27 { 28 User target = new User(null); 29 } 30 31 [TestMethod()]//方法3 32 [ExpectedException(typeof(ArgumentException))] 33 public void ConstructorTestEmpty() 34 { 35 User target = new User(""); 36 } 37 38 [TestMethod()]//方法4 39 [ExpectedException(typeof(ArgumentNullException))] 40 public void ConstructorTestBlank() 41 { 42 User target = new User(" "); 43 } 44 } 45 }
测试结果会和参考文章所说的一样报错:
和参考所说的一样在Class1.cs里增加几行代码,完整代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ClassLibrary1 { public class User { public User(string userEmail) { m_email = userEmail; if (!m_email.Contains("@")) { throw new ArgumentException(); } } private string m_email; //user email as user id } }
7.运行结果
可以看到覆盖率为85.71%,基本和参考文章的一样