敏捷实践之单元测试及最佳实践

导语

本文是敏捷实践——从什么是单元测试,为什么使用单元测试等方面阐述了单元测试的必要性;同时结合最佳实践以方便读者理解。

前言

在工作中或者在面试中,我经常碰到的开发人员就是对单元测试不重视,这一类基本上都表现出了一种“无知的自信”,总觉得自己写的代码质量很高,直到一次次虫子(Bug)把自己咬的头破血流时,才发现原来自己的代码已经到了剪不断理还乱的状态,而每次修改一个bug,都需要走一遍“墨镜迷宫” (看上图)。还有很多人知道单元测试或者写出了单元测试,但是就是写了一个方法,上面标注了一个[Test]属性而已,甚至很多的人单元测试上面标注的是[IgnoreTest], 每次看见这些,我都深深的感到推行单元测试之路是艰难的,是遥远的,但是我依然坚信是可望也可及的。只要有着深深的信念,坚强的意志,无谓的勇气,一头扎进去泥巴堆里,假以时日,当大雨来临,必将带走泥巴,从此你拔剑扬眉。哦,你不用拔剑了,因为你就是剑……

 

为了让更多人能够拔剑扬眉,也为了我们公司刚入职的新人做一些培训,我精心准备了单元测试的一些知识,在此为你奉上,我尽量用简短的语句来描述,如果你不清楚我说的某一些点,那么欢迎你发邮件给我 ,我可以针对集中的点发篇文章,如果你想知道我说的所有点怎么实践,那就联系我,试试加入到我们公司来。

 

  • 前言

  • 什么是单元测试

  • 为什么要使用单元测试

  • 单元测试难以推动的原因

    • 太花时间

    • 测试不是我的工作

    • 系统可测试性差

  • 单元测试最佳实践

    • 实践一: 三到五步

    • 实践二: 运行快速

    • 实践三:一致性

    • 实践四:原子性

    • 实践五:单一职责

    • 实践六:独立无耦合

    • 实践七:隔离外部调用

    • 实践八: 自描述

    • 实践九: 单元测试逻辑

    • 实践十: 断言

    • 实践十一:产品代码

  • 最后,单元测试常用技术及工具

什么是单元测试

单元测试是开发者编写的一小段代码,用于检验被测代码中的一个很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。

执行单元测试,是为了证明某段代码的行为确实和开发者所期望的一致。因此,我们所要测试的是规模很小的、非常独立的功能片段。通过对所有单独部分的行为建立起信心。然后,才能开始测试整个系统。

为什么要使用单元测试

  • 单元测试使工作完成的更轻松

  • 单元测试使你的设计更好

  • 大大减少花在调试上的时间

  • 能帮助你更好的理解代码

 

没有单元测试

  • 任何代码都是在假定其他代码是正确无误的情况下编写的。

  • 修改一处代码时无法得知会对其他代码产生怎样的影响。

  • 任何一处改动都需要进行功能级别的整体调试

单元测试难以推动的原因

太花时间 

很多人认为单元测试很花时间,但是想想我们在下面几点花的时间:

我经常看到为了测试一个简单的API方法,我们很多人必须让前端跑起来,甚至自己写一个客户端才能调用 ;

 调试上花的时间 ,对自认为正确的代码,花了多少时间确认代码是正确的;

定位Bug所耗的时间。

 

测试不是我的工作

很多人认为测试不是自己的工作,但是想一想每次测试提出一个bug所花的时间,以及你改bug所花的时间,所以下面2点是很重要:

内在质量的重要性;

测试应该是辅助,好的软件是开发设计出来的,不是测试出来的。

系统可测试性差

  • 系统耦合度很高,我们需要提高我们的团队的设计能力。

单元测试最佳实践

实践一: 三到五步

  • SetUp

  • 输入

  • 调用

  • 输出

  • TearDown

 

实践二: 运行快速

为什么单元测试运行很频繁,因为它是辅助开发工作的,在开发过程中运行,如果慢影响很大。

 

多快较好?

  • 单个测试小于200ms

  • 单个测试套件小于10s

  • 整个测试小于10分钟

 

实践三:一致性

任何时候同样的输入需要同样的结果

    Date date=new Date()
    Random.next()

这样的代码都需要Mock掉,不然时间每次都不同,结果就会不一样。

实践四:原子性

** 所有的测试只有两种结果:成功和失败** 不能部分测试通过

实践五:单一职责

一个测试只验证一个行为

** 测试行为,不要测试方法 ** * 一个方法,多个行为    —–>  多个测试 * 一个行为,多个方法   —–   一个测试。这里的一个行为,多个方法一般指这个方法调用private, protected, getters, setters * 多个Assert只有在测试同一个行为时可以接受。

实践六:独立无耦合

单元测试之间无相互调用

  • 单元测试执行顺序无关

  • 不同的顺序无影响

单元测试之间不能共享状态

比如一个测试里设置了一个属性值,然后在另外一个测试里用,如果必须共享可以放到Setup里。

实践七:隔离外部调用

  • 单元测试需要快速运行,且每次结果一致,所以需要隔离一切对外部的调用。

  • 不使用具体的其它真实类,就是不要new

  • 不读数据库

  • 不读网络

  • 不读外部文件

  • 适当时候可以构造一个相同的内部文件来Mock

  • 不依赖本地时间

  • 不依赖环境变量

实践八: 自描述

  • 单元测试是开发级文档

  • 单元测试是方法的描述

640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1

 

实践九: 单元测试逻辑

  • 单元测试必须是容易读和理解的

  • 变量名,方法名,类名

  • 无条件语句,无Switch 办法:分解if到多个测试,所有的输入都是已知的,所有的结果都是一定的(Mock)

  • 无循环语句

  • 无异常捕捉 ** 测试预知的异常,用ExpectedException方法 **

 

实践十: 断言

  • 断言信息最好包含Business Information

  • 如果失败断言信息包含出错的具体信息

  • 适当时候可以封装自己的Assert 。比如:

    Assert.IsProgrammer(Jack)Return Jack. Cancooking() && Jack.CanCoding()

实践十一:产品代码

  • 产品代码无测试逻辑

不能有:

    If(global.IsTest){…}
  • 测试代码和产品代码要分离

  • 不要在产品代码里有任何只供测试用的代码

  • 使用依赖注入

最后,单元测试常用技术及工具

下面是.NET程序常用的单元测试需要的技术和工具,其它语言请自行比对。

  • 面向接口编程

  • 依赖注入(Castle, Unity, Ninject)

  • Moq

  • 测试工具(xUnit) 

  • .Net Nunit

  • 代码覆盖率测试工具Ncover

  • 自动运行测试辅助工具NCrunch

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

珍儿2022

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值