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 Django连接MySQL数据库做增删改查
Nov 07 Python
Python使用MYSQLDB实现从数据库中导出XML文件的方法
May 11 Python
在Python中操作字典之setdefault()方法的使用
May 21 Python
python数组复制拷贝的实现方法
Jun 09 Python
Python实现获取域名所用服务器的真实IP
Oct 25 Python
Python之Scrapy爬虫框架安装及使用详解
Nov 16 Python
matlab中实现矩阵删除一行或一列的方法
Apr 04 Python
对python 命令的-u参数详解
Dec 03 Python
python通过tcp发送xml报文的方法
Dec 28 Python
python飞机大战pygame游戏框架搭建操作详解
Dec 17 Python
开启Django博客的RSS功能的实现方法
Feb 17 Python
python中urllib.request和requests的使用及区别详解
May 05 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
php安全之直接用$获取值而不$_GET 字符转义
2012/06/03 PHP
php数组去重实例及分析
2013/11/26 PHP
php经典算法集锦
2015/11/14 PHP
Laravel实现批量更新多条数据
2020/04/06 PHP
读jQuery之二(两种扩展)
2011/06/11 Javascript
JQUERY简单按钮轮换选中效果实现方法
2015/05/07 Javascript
jQuery+HTML5美女瀑布流布局实现方法
2015/09/21 Javascript
动态加载js文件简单示例
2016/04/21 Javascript
探寻JavaScript中this指针指向
2016/04/23 Javascript
JS中判断字符串中出现次数最多的字符及出现的次数的简单实例
2016/06/03 Javascript
Select下拉框模糊查询功能实现代码
2016/07/22 Javascript
Vue代码分割懒加载的实现方法
2017/11/23 Javascript
vue非父子组件通信问题及解决方法
2018/06/11 Javascript
vue axios 简单封装以及思考
2018/10/09 Javascript
微信小程序在地图选择地址并返回经纬度简单示例
2018/12/03 Javascript
浅谈发布订阅模式与观察者模式
2019/04/09 Javascript
node.js中Buffer缓冲器的原理与使用方法分析
2019/11/23 Javascript
Vue数据双向绑定原理实例解析
2020/05/15 Javascript
Vue中的this.$options.data()和this.$data用法说明
2020/07/26 Javascript
老生常谈Python startswith()函数与endswith函数
2017/09/08 Python
python读取一个目录下所有txt里面的内容方法
2018/06/23 Python
Python如何调用外部系统命令
2019/08/07 Python
python下载库的步骤方法
2019/10/12 Python
python获取天气接口给指定微信好友发天气预报
2020/12/28 Python
浅谈css3中的渐进增强和优雅降级
2017/12/01 HTML / CSS
老板电器官方购物商城:老板油烟机、燃气灶、消毒柜、电烤箱
2018/05/30 全球购物
JAVA和C++的区别
2013/10/06 面试题
EJB包括(SessionBean,EntityBean)说出他们的生命周期,及如何管理事务的?
2013/02/17 面试题
公司市场专员岗位职责
2014/06/29 职场文书
知识就是力量演讲稿
2014/09/13 职场文书
老公给老婆的检讨书(精华篇)
2014/10/18 职场文书
离婚协议书格式
2015/01/26 职场文书
毕业生登记表班级意见
2015/06/05 职场文书
办公室管理规章制度
2015/08/04 职场文书
Win10系统下配置Java环境变量
2021/06/13 Java/Android
Java Spring读取和存储详细操作
2022/08/05 Java/Android