深入理解Python单元测试unittest的使用示例


Posted in Python onNovember 18, 2017

软件测试

大型软件系统的开发是一个很复杂的过程,其中因为人的因素而所产生的错误非常多,因此软件在开发过程必须要有相应的质量保证活动,而软件测试则是保证质量的关键措施。正像软件熵(software entropy)所描述的那样:一个程序从设计很好的状态开始,随着新的功能不断地加入,程序逐渐地失去了原有的结构,最终变成了一团乱麻(其实最初的"很好的状态"得加个问号)。测试的目的说起来其实很简单也极具吸引力,那就是写出高质量的软件并解决软件熵这一问题。

可惜的是,软件开发人员很少能在编码的过程中就进行软件测试,大部分软件项目都只在最终验收时才进行测试,有些项目甚至根本没有测试计划!随着软件质量意识的增强,许多软件开发组织开始转向UML、CMM、RUP、XP等软件工程方法,以期提高软件质量,并使软件开发过程更加可控,好在这些方法对测试都提出了很严格的要求,从而使得测试在软件开发过程的作用开始真正体现出来。

软件测试作为一种系统工程,涉及到整个软件开发过程的各个方面,需要管理人员、设计人员、开发人员和测试人员的共同努力。作为软件开发过程中的主要力量,现今的程序员除了要编写实现代码外,还承担着单元测试这一艰巨任务,因此必须采用新的工作模式:

  1. 编写和维护一套详尽的单元测试用例;
  2. 先构造单元测试和验收测试用例,然后再编写代码;
  3. 根据构造的测试用例来编写代码。

单元测试负责对最小的软件设计单元(模块)进行验证,它使用软件设计文档中对模块的描述作为指南,对重要的程序分支进行测试以发现模块中的错误。由于软件模块并不是一个单独的程序,为了进行单元测试还必须编写大量额外的代码,从而无形中增加了开发人员的工作量,目前解决这一问题比较好的方法是使用测试框架。测试框架是在用XP方法进行单元测试时的关键,尤其是在需要构造大量测试用例时更是如此,因为如果完全依靠手工的方式来构造和执行这些测试,肯定会变成一个花费大量时间并且单调无味的工作,而测试框架则可以很好地解决这些问题。

单元测试的重要性就不多说了,可恶的是python中有太多的单元测试框架和工具,什么unittest, testtools, subunit, coverage, testrepository, nose, mox, mock, fixtures, discover,再加上setuptools, distutils等等这些,先不说如何写单元测试,光是怎么运行单元测试就有N多种方法,再因为它是测试而非功能,是很多人没兴趣触及的东西。但是作为一个优秀的程序员,不仅要写好功能代码,写好测试代码一样的彰显你的实力。如此多的框架和工具,很容易让人困惑,困惑的原因是因为并没有理解它的基本原理,如果一些基本的概念都不清楚,怎么能够写出思路清晰的测试代码?

今天的主题就是unittest,作为标准python中的一个模块,是其它框架和工具的基础,参考资料是它的官方文档:http://docs.python.org/2.7/library/unittest.html和源代码,文档已经写的非常好了,我在这里记录的主要是它的一些重要概念、关键点以及可能会碰到的一些坑,目的在于对unittest加深理解,而不是停留在泛泛的表面层上。

unittest是一个python版本的junit,junit是java中的单元测试框架,对java的单元测试,有一句话很贴切:Keep the bar green,相信使用eclipse写过java单元测试的都心领神会。unittest实现了很多junit中的概念,比如我们非常熟悉的test case, test suite等,总之,原理都是相通的,只是用不同的语言表达出来。

在文档的开篇就介绍了unittest中的4个重要的概念:test fixture, test case, test suite, test runner,我觉得只有理解了这几个概念,才能真正的理解单元测试的基本原理,下面就主要围绕这几个概念来展开这篇文章。

首先通过查看unittest的源码,来看一下这几个概念,以及他们之间的关系,他们是如何在一起工作的,其静态类图如下:

深入理解Python单元测试unittest的使用示例

一个TestCase的实例就是一个测试用例。什么是测试用例呢?就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)。元测试(unit test)的本质也就在这里,一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某一个问题进行验证。

而多个测试用例集合在一起,就是TestSuite,而且TestSuite也可以嵌套TestSuite。

TestLoader是用来加载TestCase到TestSuite中的,其中有几个loadTestsFrom__()方法,就是从各个地方寻找TestCase,创建它们的实例,然后add到TestSuite中,再返回一个TestSuite实例。

TextTestRunner是来执行测试用例的,其中的run(test)会执行TestSuite/TestCase中的run(result)方法。

测试的结果会保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息。

这样整个流程就清楚了,首先是要写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,整个过程集成在unittest.main模块中。

现在已经涉及到了test case, test suite, test runner这三个概念了,还有test fixture没有提到,那什么是test fixture呢??在TestCase的docstring中有这样一段话:

Test authors should subclass TestCase for their own tests. Construction and deconstruction of the test's environment (‘fixture') can be implemented by overriding the ‘setUp' and ‘tearDown' methods respectively.

可见,对一个测试用例环境的搭建和销毁,是一个fixture,通过覆盖TestCase的setUp()和tearDown()方法来实现。这个有什么用呢?比如说在这个测试用例中需要访问数据库,那么可以在setUp()中建立数据库连接以及进行一些初始化,在tearDown()中清除在数据库中产生的数据,然后关闭连接。注意tearDown的过程很重要,要为以后的TestCase留下一个干净的环境。关于fixture,还有一个专门的库函数叫做fixtures,功能更加强大,以后会介绍到。

至此,概念和流程基本清楚了,下面通过简单的例子再来实践一下,就拿unittest文档上的例子吧:

深入理解Python单元测试unittest的使用示例

TestSequenceFunctions继承自unittest.TestCase,重写了setUp()方法,并且定义了三个以'test'开头的方法,那这个TestSequenceFunctions类到底是个什么呢?它是一个测试用例,还是三个测试用例?说是三个测试用例的话,它本身继承自TestCase,说是一个测试用例的话,里面又有三个test_*()方法,明显是三个测试用例。其实,我们只要看一些TestLoader是如何加载测试用例的,就一清二楚了,在loader.TestLoader类中有一个loadTestsFromTestCase()方法:

深入理解Python单元测试unittest的使用示例

getTestCaseNames()是从TestCase这个类中找所有以“test”开头的方法,然后注意第9行,在构造TestSuite对象时,其参数使用了一个map方法,即对testCaseNames中的每一个元素,使用testCaseClass为其构造对象,其结果是一个TestCase的对象集合,可以用下面的代码来分步说明:

深入理解Python单元测试unittest的使用示例

可见,对每一个以test开头的方法,都为其构建了一个TestCase对象,值得注意的是,如果没有定义test开头的方法,而是将测试代码写到了一个名为runTest的方法中,那么会为该runTest方法构建TestCase对象,如果定义了test开头的方法,就会忽略runTest方法。

至此,基本就清楚了,每一个以test开头的方法,都会为其构建TestCase对象,也就是说TestSequenceFunctions类中其实定义了三个TestCase,之所以写成这样,是为了方便,因为这几个测试用例的fixture是相同的,如果每一个测试用例单独写成一个TestCase的话,会有很多的冗余代码。

明白了这些,文档就可以很轻松的看懂了,至于怎么运行测试用例,以及其他的内容,直接看文档吧。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python 绘图和可视化详细介绍
Feb 11 Python
深入了解Python中pop和remove的使用方法
Jan 09 Python
python中多个装饰器的执行顺序详解
Oct 08 Python
python按时间排序目录下的文件实现方法
Oct 17 Python
python如何获取当前文件夹下所有文件名详解
Jan 25 Python
Python 异常的捕获、异常的传递与主动抛出异常操作示例
Sep 23 Python
Pyqt5自适应布局实例
Dec 13 Python
Python reshape的用法及多个二维数组合并为三维数组的实例
Feb 07 Python
基于python连接oracle导并出数据文件
Apr 28 Python
django form和field具体方法和属性说明
Jul 09 Python
Python将字典转换为XML的方法
Aug 01 Python
Python 避免字典和元组的多重嵌套问题
Jul 15 Python
Python及PyCharm下载与安装教程
Nov 18 #Python
Python实现读取json文件到excel表
Nov 18 #Python
浅谈python 线程池threadpool之实现
Nov 17 #Python
python线程池(threadpool)模块使用笔记详解
Nov 17 #Python
python交互式图形编程实例(三)
Nov 17 #Python
R语言 vs Python对比:数据分析哪家强?
Nov 17 #Python
python交互式图形编程实例(二)
Nov 17 #Python
You might like
关于php mvc开发模式的感想
2011/06/28 PHP
php 模拟post_验证页面的返回状态(实例讲解)
2013/10/28 PHP
PHP实现git部署的方法教程
2017/12/19 PHP
php实现表单提交上传文件功能
2018/05/28 PHP
2007/12/23更新创意无限,简单实用(javascript log)
2007/12/24 Javascript
常用的JavaScript验证正则表达式汇总
2013/11/26 Javascript
基于javascript实现图片左右切换效果
2016/01/25 Javascript
Angularjs中UI Router全攻略
2016/01/29 Javascript
详谈JavaScript的闭包及应用
2017/01/17 Javascript
JavaScript限制在客户区可见范围的拖拽(解决scrollLeft和scrollTop的问题)(2)
2017/05/17 Javascript
浅谈Node.js 子进程与应用场景
2018/01/24 Javascript
详解vue移动端项目的适配(以mint-ui为例)
2018/08/17 Javascript
vue 中引用gojs绘制E-R图的方法示例
2018/08/24 Javascript
使用angular-cli webpack创建多个包的方法
2018/10/16 Javascript
如何手动实现es5中的bind方法详解
2018/12/07 Javascript
javascript+HTML5 canvas绘制时钟功能示例
2019/05/15 Javascript
VUE实时监听元素距离顶部高度的操作
2020/07/29 Javascript
[03:58]兄弟们,回来开黑了!DOTA2昔日战友招募宣传视频
2016/07/17 DOTA
python实现自动登录人人网并采集信息的方法
2015/06/28 Python
python 垃圾收集机制的实例详解
2017/08/20 Python
简单了解python的一些位运算技巧
2019/07/13 Python
python中的时区问题
2021/01/14 Python
使用HTML5技术开发一个属于自己的超酷颜色选择器
2013/09/22 HTML / CSS
html5简介_动力节点Java学院整理
2017/07/07 HTML / CSS
HTML5 表单验证失败的提示语问题
2017/07/13 HTML / CSS
东方通信股份有限公司VC面试题
2014/08/27 面试题
几道数据库的面试题或笔试题
2014/05/31 面试题
上课迟到检讨书
2014/01/19 职场文书
人事主管岗位职责
2014/01/30 职场文书
幼儿园优秀教师事迹
2014/02/13 职场文书
安全责任书范文
2014/03/12 职场文书
团队口号大全
2014/06/06 职场文书
员工安全责任书范本
2014/07/24 职场文书
未中标通知书
2015/04/17 职场文书
建国大业观后感800字
2015/06/01 职场文书
Win10防火墙白名单怎么设置?Win10添加防火墙白名单方法
2022/04/06 数码科技