本文是个人对于UT的一些想法和总结,参考时建议请查阅官方资料。

转载请注明出处:http://www.cnblogs.com/sizzle/p/4476392.html

测试思想

编写UT测试代码,通常是为了达到下面几个目的:

  • 在程序可以运行前确认部分模块的正确性。
  • 实行自动测试,减少人力成本。
  • 增加测试手段,降低bug到下游的概率。
  • 明确变更代码时产生的影响。

但是在实际的开发过程中,UT做成后很难达成以上目标,反而会产生一些副作用:

  • UT代码难于编写导致成本增加。
  • 使用UT检测出的bug量少,甚至在初期检测出的bug都是UT编写错误而引入的无效bug。

以上问题发生的原因是开发人员在设计和编码时没有考虑可测试性,导致UT容易发生弊大于利的情况。
在设计和编码时充分考虑可测试性,需要具备丰富的测试经验,而且难于达成,因此产生了”测试驱动开发“(Test Driven Development,简称TDD)。
TDD的测试做成过程很简单,基本可以概括为以下步骤:

  1. 根据需求和接口式样书编写测试代码,验证接下来编写的功能代码是否满足期待实现的需求点(此时的测试结果是NG)。
  2. 编写功能代码。
  3. 确认测试结果,如果NG需要修改功能代码或测试代码,如果OK则从1步骤开始实现下一个需求点或完善功能代码。

总之,TDD过程就是先写期待实现功能的测试代码,然后实装代码使测试通过的。当然,设计时是要优先考虑可测试性的,才能确保TDD过程更顺畅。
使用TDD思想开发的好处有很多,不做详细介绍,感兴趣可以baidu ”TDD 测试驱动开发“关键字,资料很多。
但是,即使利用TDD,开发过程中难免会出现一些测试相关问题:

  • UT结果NG,但是测试程序输出信息难于定位问题原因。
  • 测试条件混乱,导致UT代码频繁变更。
  • 维护人员基于代码难于分析出测试的内容。

以上问题在开发过程中难于避免,而且随着代码规模增加可能会爆发甚至导致UT被废弃不用。
为了减少该类问题发生,控制其增长的趋势,新的思想被引入到测试开发过程中--“行为驱动开发”(Behavior Driven Development,简称BDD)。
BDD其实是一种解决方案,它在TDD的基础上提出使用类似自然语言的方式描述软件的行为过程,从而使代码与需求说明更相近,可以与需求同步变化,因此代码也就容易理解和维护。
根据BDD一条Test case可以概括表示为下面三个阶段,测试代码也需要按照下面三段式上下文做成。

  1. Given:给出...前提条件。
  2. When:当执行...动作后。
  3. Then:那么应该得到...结果。

现在已经有很多基于BDD的测试框架,Java有JBehave,Ruby有RSpec和Cucumber,Object-C有Kiwi,Swift有Quick C++有CppSpec等。基于这些框架,我们可以写出优美的测试代码。下图是基于Swift语言使用Quick框架编写的测试代码以及对应的三段式上下文描述供参考:

测试范围

理论上,基于BDD开发,全部代码都需要测试,而且UT是针对“行为”,应该可以对应到明确的函数方法。但是实际开发过程中,有许多范围需要明确。

  • 类对象间存在关联,所谓“行为”具体需要涉及哪些对象。
  • 开发的功能依赖于第三方模块提供一些接口时,如何测试这些“行为”。
  • 通常执行测试的模块与被测模块是相互独立的,那么被测模块需要对外公开哪些数据和接口。

下面列举一些确定测试范围的“教条”,所谓“教条”就是只需灵活运用,不必刻意追求:

  1. 测试的“行为”要简单,也就是一条Test case的Assert最好只有一句。
  2. 基于“行为”测试,那么尽量不要公开数据,如果想要测试数据,那么应测试提供数据的方法(Swift中的只读计算属性,相当于提供数据的方法)。
  3. 测试的“行为”是内部的,第三方模块提供的接口属于外部“行为”,不需要测试。

在开发过程中,测试与设计相辅相成,设计时需要考虑程序的可测试性,测试时可以看出模块间的耦合是否过于紧密,模块的功能是否单一,从而驱动架构改善,减少项目后期因设计问题导致重构而产生的工数和关联功能间的影响。因此,在设计阶段就需要明确测试范围,规范模块间和模块内的“行为”,相应的测试代码就会简单明晰。

明确测试范围后,对于测试范围外而且依赖的对象需要做成Mocker,如下图所示:

如果测试模块B,那么需要做成Tester,以使用者A的角度测试B的“行为”是否满足期待值。其中模块C和D被B依赖,因此需要做成相应的Mocker,提供接口供B使用。Tester可以确认Mocker中收到的B传送的数据,从而测试B的“行为”是否正确。

测试观点

  • 条件测试:代码中存在条件语句时,注意多条件表达式组合情况下各种状态确认(即true与false的组合)。注意短路求值情况。
  • 边界测试:注意明确区间(闭区间,开区间,半闭半开区间),确认范围内值,边界值和越界值的情况,常见有数组,比较运算等。
  • 除零测试:注意确认除数是否可能未0。
  • 数值越界测试:注意值类型(有符号,无符号,各类型值范围)。
  • 空对象测试:注意是否存在操作空对象的情况。
  • 多返回测试:函数或语句块存在多出口时,注意考虑测试。
  • 非法参数测试:注意确认存在非法入参时,函数的动作是否正常。

测试标准

  1. 函数覆盖(Function coverage):度量程序中每个函数是否被执行到。
  2. 语句覆盖(Statement coverage):度量被测代码中每个可执行语句是否被执行到。
  3. 分支覆盖(Branch coverage):度量程序中每一个判定的分支是否都被测试到。
  4. 条件覆盖(Condition coverage):度量判定中的每个子表达式结果true和false是否被测试到

命名规范

  • 一个测试文件所包含的是一组对于行为的描述(Spec),因此习惯上使用需要测试的目标类来作为名字,并以Spec作为文件名后缀。
  • describe描述需要测试的对象内容,也即我们三段式中的Given。
  • context描述测试上下文,也就是这个测试在When来进行,一个describe可以包含多个context,来描述类在不同情景下的行为。
  • it中的是测试的本体,描述了这个测试应该满足的条件,一个context可以包含多个it的测试例。

关于UT的一些总结的更多相关文章

  1. 基于lcov实现的增量代码UT覆盖率检查

    背景介绍 配合CppUTest单元测试框架,lcov提供了一套比较完整的工程工具来对UT覆盖率进行度量.但对有些团队来说,历史负担太重,大量的遗留代码没有相应的UT.在这种情况下,对新增代码进行覆盖率 ...

  2. [小北De编程手记] : Lesson 05 玩转 xUnit.Net 之 从Assert谈UT框架实践

    这一篇,本文会介绍一下基本的断言概念,但重点会放在企业级单元测试的相关功能上面.下面来跟大家分享一下xUnit.Net的断言,主要涉及到以下内容: 关于断言的概念 xUnit.Net常用的断言 关于单 ...

  3. 软件开发中的完整测试所包括的环节UT、IT、ST、UAT

    软件开发中的完成测试环境所包括的环节包括:UT.IT.ST.UAT UT = Unit Test 单元测试 IT = System Integration Test 集成测试ST = System T ...

  4. Sonar + Jacoco,强悍的UT, IT 双覆盖率统计(转)

    以前做统计代码测试覆盖,一般用Cobertura.以前统计测试覆盖率,一般只算Unit Test,或者闭上眼睛把Unit Test和Integration Test一起算. 但是,我们已经过了迷信UT ...

  5. 单元测试(UT)、功能测试(FT)(转)

    纯个人总结: 单元测试(UT).功能测试(FT): 目的:1.尽量避免写的代码测试人员频繁的来找你其他地方又出问题了:2.提供的接口不可用:3.一个bug修复了引入了其他的bug或者其他用例变红了: ...

  6. [UT]Unit Test理解

    Coding中有一个原则:Test Driven Development.  UT中的一些基本概念: 1. 测试驱动 2. 测试桩 3. 测试覆盖 4. 覆盖率 单体测试内容: 1. 模块接口:测试模 ...

  7. UT技巧

    (一)PowerMockito进行UT测试如何略过方法,使方法不被执行(含私有方法): PowerMockito.doNothing().when(TestMock.class,"foo1& ...

  8. 论UT阶段重要性

    测试与开发这对立的命运啊 如果是对测试从业者心存鄙视的朋友啊,请关掉此页,带着偏见不好看的~ 人生就像一个旅途,每个人看到风景不一样,世界观.人生观.价值观也就不同.不要试着去改变别人,因为你的观点在 ...

  9. 记录一次mybatis缓存和事务传播行为导致ut挂的排查过程

    起因 rhea项目有两个ut一直都是挂的,之前也经过几个同事排查过,但是都没有找到解决办法,慢慢的这个问题就搁置了.因为之前负责rhea项目的同事离职,我临时接手了这个项目,刚好最近来了一个新同事在做 ...

随机推荐

  1. 总结:Unity3D游戏上线后的流程回顾

    原地址:http://unity3d.9tech.cn/news/2014/0127/39748.html 首先.unity 灯光烘焙 :Unity 3d FBX模型导入.选项Model 不导入资源球 ...

  2. 【redis】02string类型和hash类型

    Redis的数据类型   Redis主要分为五个数据类型,一个是string,最简单的一个数据类型,hash,list, 还有set集合,还有zset有序集合,这是咱们redis的五种基础类型, 接下 ...

  3. C#委托及事件

    转载:http://www.cnblogs.com/warensoft/archive/2010/03/19/1689806.html C#委托及事件 在C#中,委托(delegate)是一种引用类型 ...

  4. PhotoSwipe简介(PhotoSwipe是一个适合在触摸屏手机上使用的相册展示包)

    官方介绍PhotoSwipe 是专为移动触摸设备设计的相册/画廊.兼容所有iPhone.iPad.黑莓6+,以及桌面浏览器.底层实现基于HTML/CSS/JavaScript,是一款免费开源的相册产品 ...

  5. SQL server 复习一

    第一天 下面我们从最基础的开始: 在运行里面输入:services.msc 一.启动服务 二.数据库登录的两种身份验证方式 另外一种身份验证方式就是SQL Server身份验证. sa不能使用的时候可 ...

  6. Lambda Action Func练习

    namespace lambda { delegate void TestDelegate(string s); class Program { static void Main(string[] a ...

  7. ASP.Net WebForm学习笔记:一、aspx与服务器控件探秘

    作者:周旭龙 出处:http://edisonchou.cnblogs.com 开篇:毫无疑问,ASP.Net WebForm是微软推出的一个跨时代的Web开发模式,它将WinForm开发模式的快捷便 ...

  8. 为什么重写equals方法还要重写hashcode方法?

    我们都知道Java语言是完全面向对象的,在java中,所有的对象都是继承于Object类.Ojbect类中有两个方法equals.hashCode,这两个方法都是用来比较两个对象是否相等的. 在未重写 ...

  9. Ubuntu下编译运行Kamailio

    kamailio----配置没有成功,这个文档过几天删除,因为这个项目的文档非常少,而且qq群里的人也不活跃,现在正在研究Freeswitch,如果能够满足,就不研究这个了,这篇文档会删除. Kama ...

  10. 10个用于Web开发的最好 Python 框架

    Python 是一门动态.面向对象语言.其最初就是作为一门面向对象语言设计的,并且在后期又加入了一些更高级的特性.除了语言本身的设计目的之外,Python标准 库也是值得大家称赞的,Python甚至还 ...