单元测试xUnit学习

为什么要做自动化测试

  • 可以频繁的进行测试
  • 可以在任何时候进行测试,也可以按计划定时测试
  • 比人工测试快
  • 快速发现错误
  • 可靠
  • 测试代码与生产代码紧密结合
  • 代码规范

自动化测试的分类

单元测试:可以测试某个类或方法,具有较高的深度,对应用的功能覆盖面很小。

  • 集成测试:有更好的广度,可以测试web资源,数据库资源等。
  • 皮下测试:在web中针对controller下的节点测试。
  • UI测试:是对应用的界面功能测试。
    常用的是单元测试和集成测试。
    在这里插入图片描述

什么是单元测试

一个单元测试是一段自动化的代码,这段代码调用被测试的工作单元,对这个单元的单个最终结果的某些假设进行验证。单元测试用单元测试框架编写,容易编写、快速运行、测试可靠、可读、可维护。只要产品代码不发生变化则单元测试的结果是稳定的。

传统单元测试开发流程
在这里插入图片描述
测试驱动开发(Test Driven Development ,TDD)流程
在这里插入图片描述

测试命名基本规则

  • 项目:[ProjectUnderTest].UnitTests
  • 类:[ClassName]Tests
  • 工作单元(方法):[UnitOfWorkName][ScenarioUnderTest][ExpectedBehavior]
    UnitOfWorkName被测试的方法,一组方法或者一组类。Scenario测试进行的假设条件
    ExpectedBehavior在测试进行的假设条件下,对测试方法行为的预期。测试方法的行为有三种可能结果:返回一个值(一个真实值,或者一个异常);改变系统状态(例如在系统中添加一个用户,导致在下次登入时系统的行为发生变化);调用第三方系统(例如一个外部的Web服务)。

测试单元命名举例:对IsValidLogFileName方法进行测试,假设条件是给方法传入一个有效的文件类型,预期行为是方法返回一个值True。则可以把测试命名为IsValidLogFileName_BadExtension_ReturnFalse

测试三阶段AAA

  • 准备(Arrange):做一些先决条件,例如创建对象实例,数据,输入等等。
  • 操作(Arc):执行生产代码并返回结果,例如调用方法,或这设置属性。
  • 断言(Assert):检查结果,测试通过或失败。

优秀的单元测试

无论如何组织测试,无论有多少测试,如果不能信任、维护和阅读它们,这些测试就几乎没有价值,要写优秀的单元测试,它们应同时具备三属性:1、可靠性;2、可维护性;3、可读性。

  • 编写可靠的测试

    • 决定何时删除或修改测试

      • 产品缺陷
      • 测试缺陷
      • 语义或者API变更
      • 冲突或者无效的测试
      • 重命名或者重构测试
      • 删除重复测试
    • 避免测试中的逻辑分支判断
      单元测试不应该有逻辑:switch、if else语句,foreach、for或while循环。因为这样的 测试可读性较差,也比较脆弱,增加测试代码复杂度,容易包含隐藏缺陷。

    • 只测试一个关注点
      一个关注点是一个单元测试的一个最终结果:一个返回值,系统状态的一个改变或对第三方对象的一个调用。在一个单元测试中验证多个关注点使测试变得复杂,应该对每个关注点的测试分开的独立的验证。

    • 把单元测试和集成测试分开

    • 用代码审查确保代码覆盖率

  • 编写维护的测试

    • 测试私有或受保护的方法
      开发人员把方法设为私有或者受保护的,通常有着充分的理由。有时是为了隐藏实现细节,以便将来实现的变化不会影响外部功能。也可能是出于安全或者知识产权相关的原因。如果一个私有方法值得进行测试,那么它也许应该设为公共的,静态的或者至少是内部的,并且定义使用它的公共契约。这也是TDD相比传统测试的一个有点,可以避免不必要的重构。
      • 使方法成为公共方法
      • 把方法抽取到新类
      • 使方法成为静态方法
      • 使方法成为内部方法结合特性,让测试可以调用该方法
  • 去除重复测试代码

  • 编写可读测试

    • 单元测试命名规范
    • 有意义的断言
    • 断言和操作分离

xUnit测试框架

xUnit官网
xUnit源码
xUnit案例
xUnit文档

支持平台:

  • .NET Framework
  • .NET Core
  • .NET Standard
  • UWP
  • Xamarin

特点:

  • 支持多平台
  • 并行测试
  • 数据驱动测试
  • 可扩展

产品代码、测试代码、测试工具的关系:
测试项目需要引用被测试项目从而进行测试,测试项目同时需要引用xUnit库。测试编写好后用Test Runner来运行测试。Test Runner可以读取测试代码,并且会知道我们所使用的测试框架,然后执行,并显示结果。目前可用的Test Runner包括vs自带的Test Explorer或者dotnet core命令行,以及第三方工具,例如resharper等。
在这里插入图片描述

什么是Assert

Assert基于代码的返回值,对象的最终状态,事件是否发生等情况来评估测试的结果。
Assert的结果可能是Pass或者Fail。如果所有的assert都pass了,那么整个测试就成功了;如果有任何assert fail了,那么测试就失败 。

xUnit提供了一下类型的assert

  • boolean:true/fale
  • String:相等/不等;是否为空;以…开始/结束;是否包含子字符串;匹配正则表达式。
  • 数值型:相等/不相等;是否在某个范围内;浮点的精度。
  • Collection:内容是否相等;是否包含某个元素;是否包含满足某种条件(predicate)的元素;是否所有的元素都满足某个assert。
  • Raised events:Custom events;Framework events(例如:PropertyChanged)。
  • Object Type:是否是某种类型;是否某种类型或继承与某种类型。
  • Assert.Throws:断言异常。
  • Assert.Raises:断言事件。
  • Assert.PropertyChanged:断言属性改变事件是否触发。

建议每个test方法里面只有一个assert;或者每个test里可以有多个assert,但是这些assert都要针对同一个行为。

测试方法管理优化

  • 测试分组:[Trait(“Name”, “Value”)] 方法级,类级。
  • 或略测试[Fact(Skip = “暂时忽略这个测试”)]
  • 自定义测试输出内容:ITestOutputHelper,使用该Helper需要构造函数注入。
  • 减少重复代码
  • 重构代码
  • 共享上下文:同一个测试类中共享,测试实现共享上下文需要测试继承共享资源类的IClassFixture泛型类型接口,并在构造函数中注入该实例。共享资源,只创建一次,防止运行每个测试方法调用构造函数重复创建资源。不同的测试类中共享。测试类统一标志CollectionDefinition特性,如:[CollectionDefinition(“Lone Time Task Collection”)]用来实现不同测试类对同一实例的共享。

数据驱动测试

使用[Theory]属性来测试几个不同的数据输入,数据来源:

  • [InlineData]
  • [MemberData(nameof(xxx), MemberType = typeof(xxx))]
  • 自定义特性继承自DataAttribute的数据
  • 外部数据源

学习代码

参考:
《单元测试的艺术 第二版》
https://www.cnblogs.com/cgzl/p/8283610.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值