Team Test 是 Visual Studio Test System 集成的单元测试框架,它支持:
- 测试方法存根 (stub) 的代码生成。
- 在 IDE 中运行测试。
- 合并从数据库中加载的测试数据。
- 测试运行完成后,进行代码覆盖分析。
2、
测试存根的生成:
- 单元测试是对某个方法的测试,因此测试的单位是方法;
- 右键点击类或者方法,“创建单元测试”;
- 自动生成单元测试存根时,可以选择为一个类下的多个方法同时生成单元测试代码。
- VSTT支持对私有方法的测试,这时你可能会看到一些利用反射机制生成的代理类。(与NUnit不同)。
测试项目的结构组织:
- 首先需要将测试代码组织到单独的测试项目中,保持产品代码的干净。(VS支持专门的测试类项目);
- 生成的测试项目包含了对 Microsoft.VisualStudio.QualityTools.UnitTestFramework和 待测试项目的引用。
- 建议每个目标类对应一个测试类,物理上对应一个.cs文件;
测试代码实现:
- 测试类的结构:
- 每个待测试目标类生成一个对应的加上 [TestClass()]声明的测试类;
- 关于目标类的每个方法,对应测试类中的一个用 [TestMethod()]声明的方法;测试方法的签名必须是无参数的实例方法
- [ClassInitialize()]和[ClassCleanup()]标识的静态方法,表示测试类的初始化代码和测试类中所有单元测试执行完毕后执行的方法;
- [TestInitialize()]和[TestCleanup()]标识的实例方法,表示每个单元测试执行前都要运行的一段代码;
- Team Test 使用反射机制在测试程序集中搜索所有由 TestClassAttribute 修饰的类,然后查找由 TestMethodAttribute 修饰的方法来决定执行的内容
- 测试断言类Assert
- Assert断言类是用来判断测试是否通过的关键类,它里面有各种各样强大的测试方法,如果这些方法没有获得预期的结果,那么测试失败。
- 一个测试中可以有多个测试断言。
- Assert断言中的出错提示应尽可能的准确和明白。
- 使用 Assert.Inconclusive("TODO: 实现用来验证目标的代码")来表示一些尚未完全实现的测试,此时测试结果表现为一个不同于“通过”和“未通过”的第三种状态。
- 期待异常:
- 一般方法:
[ExpectedException(typeof(ArgumentException),
"A userId of null was inappropriately allowed.")]
- 更灵活的方法:
在测试方法中try和catch,然后比较catch到得异常的类型和你预期的异常的类型是否相同使用,不同则报错:
Assert.IsNotNull(exception,
"The expected exception was not thrown.");
Assert.AreEqual<Type>(
typeof(ArgumentException), exception.GetType(),
"The exception type was unexpected.");
5、
- 可以使用“测试列表编辑器”来控制想要运行的测试
- 将光标定位到一个测试方法,运行测试,则会只运行该测试;如果光标位于所有方法前面,则运行当前上下文中(当前类)的所有测试
- “测试”菜单--->“测试视图”--->选中一个测试右键--->“属性”--->可以设置测试的各种属性。
测试结果的观察分析:
- 可以查看所有的历史测试结果,并且可以管理当前正在执行的测试;
- 测试表单上方的测试总结链接,可以统计性的观察所有测试的执行情况。双击具体的测试条目可以看到具体测试的执行结果情况,支持非常丰富的测试记录信息;
- 测试条目较多时,可以用不同的“分组依据”来方便的观察结果,也可以使用测试结果的自定义快速检索查找感兴趣的测试;
- 右键点击测试,可以看到一个“打开测试”的菜单项,可以方便的定义出错的测试,进而定位到目标方法;
- 在测试结果窗体中也可以有选择的重新执行某些测试;
- 通过测试报告的时间对比,可以用来做性能调优的一个参照。
代码覆盖:
- 该功能只是在VS团队开发版中才有,专业版中不具备该功能
- 打开方法:
- 菜单:测试-->编辑测试运行配置-->选择你的配置
- 配置:选中你要做覆盖率统计的模块,然后重新执行测试,既可以看到覆盖率统计结果了
- 可以详细解释被执行代码的百分率,并用颜色突出显示哪些代码被执行,那些没有被执行。
- 红色突出显示说明了我们有产品代码没有运行任何单元测试,这说明我们编写这些代码时未遵循 TDD 原则,即在编写实现前先提供测试。
从数据库中加载测试数据:
- 提供一个测试值的集合用于验证实现 ---- 数据驱动测试;
- 库的两种选择:
- 文件性:
- 项目 -> 增加新项-->“本地数据库”或者“基于服务的数据库”,然后“工具” ->“ 连接到数据库”,最后从“服务器资源管理器”修改该库的结构,如创建表
- 特点:移植性好,大数据量支持不好
- 数据库性:
- 直接使用服务器资源管理器添加库
- 特点:与文件性相反
- 文件性:
- 打开“测试视图”,选中一个测试编辑其属性,给他赋予一个数据库连接的属性;
- 设置数据库连接字符串和连接的测试数据表
- 这样做IDE将使用附加的属性 DataSourceAttribute 和 DataTableNameAttribute 更新自动生成的测试代码。
- 使用TextContext的DataRow属性来访问你关联的数据;你不用控制循环遍历表的内容,由测试框架来自动遍历表格的每一条记录;
- 测试数据的结构
- 一般包含测试数据本身和预期结果字段两部分
- 预期结果可能是一个true或者false的标识
- 测试数据的组织是十分灵活和讲究技巧的
- 查看测试结果详细信息时,会发现结果展示为“数据驱动测试结果”
测试驱动开发方法的实践:
- 在实现类的方法前,先编写对方法的测试;
- 然后完善方法,使测试通过,则功能完成。
- 单元测试的真正价值在代码修改的时候才真正有所体现,一套单元测试可以保证我们在维护和改进代码的时候没有破坏代码。
- 在所有现有的开发方法中,TDD 可能是多年来根本上改进开发且投资成本最小的一种。
- 需要训练来开始养成习惯,但一旦建立习惯后,不使用 TDD 方法编码就像开车时不系安全带一样。
单元测试最佳实践:
- 避免测试产生依赖性,这样测试需要按照特定的顺序执行。每个测试都应该是自治的。
- 避免创建其他依赖计算机的测试,例如依赖特定的目录路径的测试。
- 对于产品代码中的每个类创建一个测试类。这样可以简化测试的组织,并可以容易地选择在何处放置每个测试。
- 在继续创建新的测试前验证所有测试运行成功,这样可以保证在破坏代码后立刻进行修正。
- 在依赖于手工测试前,必须完全肯定无法采用合理的自动测试方案。