本文是个人对于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. 弱弱的玩下Javascript

    前言 好久没有更新博客了,也蛮少捣弄javascript,今儿看到一个题目,关于给你一个面板,你可以随意的在上面画矩形,可以移动和删除任意一个你创建的矩形,心血来潮搞着玩哈,实现起来挺简单的,但这代码 ...

  2. Even Fibonacci numbers

    --Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting ...

  3. Class Object

    java.lang Class Object java.lang.Object public class Object Class Object is the root of the class hi ...

  4. POJ2104 K-th number 函数式线段树

    很久没打代码了,不知道为什么,昨天考岭南文化之前突然开始思考起这个问题来,这个问题据说有很多种方法,划分树什么的,不过对于我现在这种水平还是用熟悉的线段树做比较好.这到题今年8月份的时候曾经做过,那个 ...

  5. 2013年山东省第四届ACM大学生程序设计竞赛 Alice and Bob

      Alice and Bob Time Limit: 1000ms   Memory limit: 65536K 题目描述 Alice and Bob like playing games very ...

  6. String类的使用 Part2

    StringBuilder 类的使用 属性: namespace StringBuilderTest { class Program { static void Main(string[] args) ...

  7. Meteor 简介

    简介 先来活动一下大脑.假设你坐在电脑面前,在两个窗口中打开同一个文件夹. 在其中一个窗口中删除一个文件,另一个窗口中的这个文件会消失吗? 不用实际操作你也知道肯定会消失的.在本地文件系统中的操作,不 ...

  8. lintcode :Valid Palindrome 有效回文串

    题目: 有效回文串 给定一个字符串,判断其是否为一个回文串.只包含字母和数字,忽略大小写. 样例 "A man, a plan, a canal: Panama" 是一个回文. & ...

  9. ADO,OLEDB,ODBC,DAO的区别

    ADO NET OLEDB ODBC连接数据库的区别 http://www.doc88.com/p-976312043296.html http://blog.csdn.net/ithomer/art ...

  10. SSH公钥认证登录

    概述: SSH登录的认证方式分为两种,一种是使用用户名密码的方式,另一种就是通过公钥认证的方式进行访问, 用户名密码登录的方式没什么好说的,本文主要介绍通过公钥认证的方式进行登录. 思路: 在客户端生 ...