python单元测试unittest实例详解


Posted in Python onMay 11, 2015

本文实例讲述了python单元测试unittest用法。分享给大家供大家参考。具体分析如下:

单元测试作为任何语言的开发者都应该是必要的,因为时隔数月后再回来调试自己的复杂程序时,其实也是很崩溃的事情。虽然会很快熟悉内容,但是修改和调试将是一件痛苦的事情,如果你在修改了代码后出现问题的话,而单元测试可以帮助我们很快准确的定位到问题的位置,出现问题的模块和单元。所以这是一件很愉快的事情,因为我们知道其它修改或没有修改的地方仍然是正常工作的,而我们目前的唯一问题就是搞定眼前这个有点问题的“家伙”。所以工作会在轻松中开始,并且很快将会结束,因为你已经知道很多信息了。
 
单元测试自然是对程序中最小的可测试模块--函数来进行测试;因为单元测试的对象是函数,也就是说你得被测试对象一定要有输出结果,哪怕就是异常输出,也得有输出,以便单元测试模块能够捕获返回值,并且与预期值进行比较,从而得出测试通过与否。
 
单元测试的加载方式有2种:一种是通过unittest.main()来启动单元测试的测试模块;一种是添加到testsuite集合中再加载所有的被测试对象,而testsuit里存放的就是单元测试的用例,下面分别列出了2种方法的使用。

1.1 测试模块中的函数:

被测模块:

#!/usr/bin/env python 
#encoding: utf-8 
def sum( x, y): 
    return x+y 
def sub( x, y): 
    return x-y

单元测试模块:

#!/usr/bin/env python 
#encoding: utf-8 
import unittest 
import myclass 
class mytest(unittest.TestCase): 
  ##初始化工作 
  def setUp(self): 
    pass 
  #退出清理工作 
  def tearDown(self): 
    pass 
  #具体的测试用例,一定要以test开头 
  def testsum(self): 
    self.assertEqual(myclass.sum(1, 2), 2, 'test sum fail') 
  def testsub(self): 
    self.assertEqual(myclass.sub(2, 1), 1, 'test sub fail')   
if __name__ =='__main__': 
  unittest.main()

测试结果:【F表示一个fail, F前的点表示一个通过,有E的话表示程序自身异常】

.F
======================================================================
FAIL: testsum (__main__.mytest)
----------------------------------------------------------------------
Traceback (most recent call last):
 File "C:\Users\xiaowu\workspace\mypython\unitTest.py", line 19, in testsum
  self.assertEqual(myclass.sum(1, 2), 2, 'test sum fail')
AssertionError: test sum fail
----------------------------------------------------------------------
Ran 2 tests in 0.001s 
FAILED (failures=1)

1.2 测试模块类中的函数:

被测模块:

#!/usr/bin/env python
#encoding: utf-8
class myclass:
  def __init__(self):
    pass
  def sum(self, x, y):
    return x+y
  def sub(self, x, y):
    return x-y

单元测试模块:

#!/usr/bin/env python 
#encoding: utf-8 
import unittest 
import myclass 
class mytest(unittest.TestCase): 
  ##初始化工作 
  def setUp(self): 
    self.tclass = myclass.myclass()
    ##实例化了被测试模块中的类 
  #退出清理工作 
  def tearDown(self): 
    pass 
  #具体的测试用例,一定要以test开头 
  def testsum(self): 
    self.assertEqual(self.tclass.sum(1, 2), 3) 
if __name__ =='__main__': 
  unittest.main()

运行结果:

.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

这种方式执行单个测试文件时使用-v参数可以获得更多的测试结果信息。如:mytest.py -v 
 
2 加载测试套件

好吧,在运用测试套件进行单元测试之前,我想还是稍微研究一下unittest模块的内容有哪些,其大概的运行方式是什么样的。而后在给出根据各种情况如何制定单元测试套件。

首先,自然是查看unittest模块有哪些成员啦!

>>import unittest 
>>dir(unittest) 
['FunctionTestCase', 'TestCase', 'TestLoader', 'TestProgram', 'TestResult', 'Tes 
tSuite', 'TextTestRunner', '_CmpToKey', '_TextTestResult', '_WritelnDecorator', 
'__all__', '__author__', '__builtins__', '__doc__', '__email__', '__file__', '__ 
metaclass__', '__name__', '__package__', '__unittest', '__version__', '_makeLoad 
er', '_strclass', 'defaultTestLoader', 'findTestCases', 'getTestCaseNames', 'mai 
n', 'makeSuite', 'os', 'sys', 'time', 'traceback', 'types']

可以看到其自身的成员也不是很多,大概包括有:

['FunctionTestCase', 'TestCase', 'TestLoader', 'TestProgram', 'TestResult',
 'TestSuite','TextTestRunner', '_CmpToKey', '_TextTestResult', '_WritelnDecorator',
 'defaultTestLoader','findTestCases', 'getTestCaseNames', 'main', 'makeSuite']

好吧,我们大概看看具体都是干什么的

>>memblist = ['FunctionTestCase', 'TestCase', 'TestLoader', 'TestProgram', 'TestResult',\ 
'TestSuite','TextTestRunner', 'defaultTestLoader','findTestCases', 'getTestCaseNames', \ 
'main', 'makeSuite'] 
>>for memb in memblist: 
.. cur = getattr(unittest, memb) 
.. print help(cur)

'FunctionTestCase':函数测试用例,即给一个函数作为参数,返回一个testcase实例,可选参数有set-up,tear-down方法
'TestCase':所有测试用例的基本类,给一个测试方法的名字,返回一个测试用例实例
'TestLoader':测试用例加载器,其包括多个加载测试用例的方法。返回一个测试套件
loadTestsFromModule(self, module)--根据给定的模块实例来获取测试用例套件
loadTestsFromName(self, name, module=None)
--根据给定的字符串来获取测试用例套件,字符串可以是模块名,测试类名,测试类中的测试方法名,或者一个可调用的是实例对象
这个实例对象返回一个测试用例或一个测试套件
loadTestsFromNames(self, names, module=None) --和上面功能相同,只不过接受的是字符串列表
loadTestsFromTestCase(self, testCaseClass)--根据给定的测试类,获取其中的所有测试方法,并返回一个测试套件
'TestProgram':命令行进行单元测试的调用方法,作用是执行一个测试用例。其实unittest.main()方法执行的就是这个命令,
而这个类实例时默认加载当前执行的作为测试对象,
原型为 __init__(self, module='__main__', defaultTest=None, argv=None, testRunner=xx, testLoader=xx)
其中module='__main__'就是默认加载自身
'TestResult':测试用例的结果保存实例,通常有测试框架调用
'TestSuite':组织测试用例的实例,支持测试用例的添加和删除,最终将传递给testRunner进行测试执行
'TextTestRunner':进行测试用例执行的实例,其中Text的意思是以文本形式显示测试结果。显示测试名称,即完成的测试结果,其过同执行单元测试脚本时添加-v参数
'defaultTestLoader':其实就是TestLoader
'findTestCases', 'getTestCaseNames':这个2个就不用解释了
'main': 其实就是TestProgram
'makeSuite':通常是由单元测试框架调用的,用于生产testsuite对象的实例
 
至此,我们知道了。其实整个单元测试框架的逻辑出来了。分三步走:第一步testloader根据传入的参数获得相应的测试用例,即对应具体的测试方法,
然后makesuite在把所有的测试用例组装成testsuite,最后把testsiute传给testrunner进行执行。
而我们通常执行的unittest.main(),其实就是unittest.testprom方法,其执行的功能就是上面分析的三步,在第一步中其传入的参数是自身的模块__main__;
在第二步中把自身模块中的所有测试类中中的测试方法提取出来,并生成测试套件;最后再把测试套件传递给testrunner进行具体的测试。

最后给出一个完整的单元测试组织代码,把该代码放到单元测试用例文件的同一个目录后执行该脚本,即可执行所有的测试用例文件。

【测试用例文件必须为test开头,如:testxxx.py, 当然这个文件本身是一个单元测试的文件】

#!/usr/bin/env python
#encoding: utf-8
#该代码源自深入python
import unittest
import myclass
import re
import os
import sys
def testAllinCurrent():
  path = os.path.abspath(os.path.dirname(sys.argv[0]))
  files = os.listdir(path)
  test = re.compile("test\.py{1}quot;, re.IGNORECASE)
  files = filter(test.search, files)
  filenameToModuleName = lambda f: os.path.splitext(f)[0]
  moduleNames = map(filenameToModuleName, files)
  modules = map(__import__, moduleNames)
  load = unittest.defaultTestLoader.loadTestsFromModule
  return unittest.TestSuite(map(load, modules))
if __name__ == "__main__":
  unittest.main(defaultTest="regressionTest")

希望本文所述对大家的Python程序设计有所帮助。

Python 相关文章推荐
Python的Tornado框架异步编程入门实例
Apr 24 Python
简述Python中的面向对象编程的概念
Apr 27 Python
python 寻找优化使成本函数最小的最优解的方法
Dec 28 Python
Django中使用Whoosh进行全文检索的方法
Mar 31 Python
如何使用Python进行OCR识别图片中的文字
Apr 01 Python
python中对数据进行各种排序的方法
Jul 02 Python
深入了解Python枚举类型的相关知识
Jul 09 Python
python实现图像检索的三种(直方图/OpenCV/哈希法)
Aug 08 Python
Python Numpy 自然数填充数组的实现
Nov 28 Python
重写django的model下的objects模型管理器方式
May 15 Python
python爬取招聘要求等信息实例
Nov 20 Python
python 获取剪切板内容的两种方法
Nov 28 Python
Python使用MYSQLDB实现从数据库中导出XML文件的方法
May 11 #Python
Python生成不重复随机值的方法
May 11 #Python
Python解析nginx日志文件
May 11 #Python
Python字符串替换实例分析
May 11 #Python
Python使用django获取用户IP地址的方法
May 11 #Python
总结Python编程中三条常用的技巧
May 11 #Python
python求解水仙花数的方法
May 11 #Python
You might like
Smarty安装配置方法
2008/04/10 PHP
php实现utf-8和GB2312编码相互转换函数代码
2013/02/07 PHP
PHP按行读取文件时删除换行符的3种方法
2014/05/04 PHP
给ECShop添加最新评论
2015/01/07 PHP
借用Google的Javascript API Loader来加速你的网站
2009/01/28 Javascript
ejs v9 javascript模板系统
2012/03/21 Javascript
js实现简易的单数字随机抽奖(0-9)
2020/03/19 Javascript
ajax跨域调用webservice的实现代码
2016/05/09 Javascript
JS实现的自动打字效果示例
2017/03/10 Javascript
使用vs code开发Nodejs程序的使用方法
2017/09/21 NodeJs
详解VueJs中的V-bind指令
2018/05/03 Javascript
微信小程序收藏功能的实现代码
2018/06/12 Javascript
vue 实现边输入边搜索功能的实例讲解
2018/09/16 Javascript
使用electron将vue-cli项目打包成exe的方法
2018/09/29 Javascript
在VUE中实现文件下载并判断状态的方法
2019/11/08 Javascript
前端开发之便利店收银系统代码
2019/12/27 Javascript
[42:04]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#3Secret VS OG第一局
2016/03/03 DOTA
python操作ssh实现服务器日志下载的方法
2015/06/03 Python
Python之re操作方法(详解)
2017/06/14 Python
Python(Django)项目与Apache的管理交互的方法
2018/05/16 Python
python实现对求解最长回文子串的动态规划算法
2018/06/02 Python
python爬取微信公众号文章的方法
2019/02/26 Python
Python中Flask-RESTful编写API接口(小白入门)
2019/12/11 Python
如何使用PyCharm将代码上传到GitHub上(图文详解)
2020/04/27 Python
试用期员工考核制度
2014/01/22 职场文书
小学生国旗下演讲稿
2014/04/25 职场文书
社区党建工作方案
2014/06/10 职场文书
学习保证书
2015/01/17 职场文书
个人工作违纪检讨书
2015/05/05 职场文书
2015年林业工作总结
2015/05/14 职场文书
2016春季幼儿园小班开学寄语
2015/12/03 职场文书
《水上飞机》教学反思
2016/02/20 职场文书
python实现的人脸识别打卡系统
2021/05/08 Python
python开发的自动化运维工具ansible详解
2021/08/07 Python
redis击穿 雪崩 穿透超详细解决方案梳理
2022/03/17 Redis
springboot 自定义配置 解决Boolean属性不生效
2022/03/18 Java/Android