python基础——单元测试

  

  如果你听说过“测试驱动开发”(TDD:Test-Driven Development),单元测试就不陌生。

  单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作

  比如对函数abs(),我们可以编写出以下几个测试用例:

    1. 输入正数,比如11.20.99,期待返回值与输入相同

    2. 输入负数,比如-1-1.2-0.99,期待返回值与输入相反

    3. 输入0,期待返回0

    4. 输入非数值类型,比如None[]{},期待抛出TypeError

  把上面的测试用例放到一个测试模块里,就是一个完整的单元测试

  如果单元测试通过,说明我们测试的这个函数能够正常工作。如果单元测试不通过,要么函数有bug,要么测试条件输入不正确,总之,需要修复使单元测试能够通过。

  单元测试通过后有什么意义呢?如果我们对abs()函数代码做了修改,只需要再跑一遍单元测试,如果通过,说明我们的修改不会对abs()函数原有的行为造成影响,如果测试不通过,说明我们的修改与原有行为不一致,要么修改代码,要么修改测试。

  这种以测试为驱动的开发模式最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的时候,可以极大程度地保证该模块行为仍然是正确的

  我们来编写一个Dict类,这个类的行为和dict一致,但是可以通过属性来访问,用起来就像下面这样:

>>> d = Dict(a=1, b=2)
>>> d['a']
1
>>> d.a
1

  mydict.py代码如下:

class Dict(dict):

    def __init__(self, **kw):
super().__init__(**kw) def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Dict' object has no attribute '%s'" % key) def __setattr__(self, key, value):
self[key] = value

  为了编写单元测试,我们需要引入Python自带的unittest模块,编写mydict_test.py如下:

import unittest

from mydict import Dict

class TestDict(unittest.TestCase):

    def test_init(self):
d = Dict(a=1, b='test')
self.assertEqual(d.a, 1)
self.assertEqual(d.b, 'test')
self.assertTrue(isinstance(d, dict)) def test_key(self):
d = Dict()
d['key'] = 'value'
self.assertEqual(d.key, 'value') def test_attr(self):
d = Dict()
d.key = 'value'
self.assertTrue('key' in d)
self.assertEqual(d['key'], 'value') def test_keyerror(self):
d = Dict()
with self.assertRaises(KeyError):
value = d['empty'] def test_attrerror(self):
d = Dict()
with self.assertRaises(AttributeError):
value = d.empty

  

  编写单元测试时,我们需要编写一个测试类,从unittest.TestCase继承。

  test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行

  对每一类测试都需要编写一个test_xxx()方法。由于unittest.TestCase提供了很多内置的条件判断,我们只需要调用这些方法就可以断言输出是否是我们所期望的。最常用的断言就是assertEqual()

self.assertEqual(abs(-1), 1) # 断言函数返回的结果与1相等

  另一种重要的断言就是期待抛出指定类型的Error,比如通过d['empty']访问不存在的key时,断言会抛出KeyError

with self.assertRaises(KeyError):
value = d['empty']

  而通过d.empty访问不存在的key时,我们期待抛出AttributeError

with self.assertRaises(AttributeError):
value = d.empty

  

运行单元测试

  一旦编写好单元测试,我们就可以运行单元测试。最简单的运行方式是在mydict_test.py的最后加上两行代码:

if __name__ == '__main__':
unittest.main()

  这样就可以把mydict_test.py当做正常的python脚本运行:

$ python mydict_test.py

  另一种方法是在命令行通过参数-m unittest直接运行单元测试:

  

  这是推荐的做法,因为这样可以一次批量运行很多单元测试,并且,有很多工具可以自动来运行这些单元测试

setUp与tearDown

  可以在单元测试中编写两个特殊的setUp()tearDown()方法。这两个方法会分别在每调用一个测试方法的前后分别被执行

  setUp()tearDown()方法有什么用呢?设想你的测试需要启动一个数据库,这时,就可以在setUp()方法中连接数据库,在tearDown()方法中关闭数据库,这样,不必在每个测试方法中重复相同的代码:

class TestDict(unittest.TestCase):

    def setUp(self):
print('setUp...') def tearDown(self):
print('tearDown...')

  可以再次运行测试看看每个测试方法调用前后是否会打印出setUp...tearDown...

小结

  单元测试可以有效地测试某个程序模块的行为,是未来重构代码的信心保证。

  单元测试的测试用例要覆盖常用的输入组合、边界条件和异常

  单元测试代码要非常简单,如果测试代码太复杂,那么测试代码本身就可能有bug

  单元测试通过了并不意味着程序就没有bug了,但是不通过程序肯定有bug。

参考源码:

  mydict.py:

 #python 单元测试   示例
#该文件编写一个Dict类,这个类的行为和dict一致,但是可以通过属性来访问
#2016-8-31 21:57:18
#MengmengCoding
# -*- coding: utf-8 -*- class Dict(dict): def __init__(self,**kw):
super().__init__(**kw) #继承dict类的初始化功能 def __getattr__(self,key):
#当使用点号获取实例属性时,如果属性不存在就自动调用__getattr__方法
#调用时,执行self[key],此为dict类的方法,只要key存在,即可正确执行
#如此,即可使用‘.’运算符实现字典的查看功能
try:
return self[key]
except KeyError:
raise AttributeError(r"'Dict' object has no attribute '%s'" % key) def __setattr__(self,key,value):
#设置类实例属性时自动调用,如j.name=5 就会调用__setattr__方法
#该方法执行self[key]=value,此为dict类中字典的赋值方法。
#如此,即可实现使用‘.’运算符实现字典的赋值功能
self[key]=value

  mydict_test.py:

 #python 单元测试   示例
#该文件编写单元测试用例,用于测试mydict.py中的Dict类的方法
#2016-8-31 22:21:52
#MengmengCoding
# -*- coding: utf-8 -*- #为了编写单元测试,我们需要引入Python自带的unittest模块 import unittest from mydict import Dict class TestDict(unittest.TestCase): def setUp(self): #每调用一个测试方法前会执行
print('setUp...') def tearDown(self): #每调用一个测试方法后会执行
print('testDown...')
#以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。
def test_init(self): #测试Dict类是否能同dict一样初始化
d=Dict(a=1,b='test')
self.assertEqual(d.a,1)
self.assertEqual(d.b,'test')
self.assertTrue(isinstance(d,dict)) def test_key(self): #测试键值是否对应
d=Dict()
d['key']='value'
self.assertEqual(d.key,'value') def test_attr(self): #测试属性方法是否正确
d=Dict()
d.key='value' #测试‘.’属性和赋值属性
self.assertTrue('key' in d)#d中是否有key键
self.assertEqual(d['key'],'value')#测试d.key='value'这种赋值方法是否奏效 def test_keyerror(self):
d=Dict()
with self.assertRaises(KeyError): #期待抛出指定类型的Error(KeyError)
value=d['empty'] def test_attrerror(self):
d=Dict()
with self.assertRaises(AttributeError): #期待抛出指定类型的Error(AttributeError)
value=d.empty if __name__ =='__main__':
unittest.main()

  

python基础——单元测试的更多相关文章

  1. python基础===单元测试unittest

    ''' 编写一个名为Employee 的类,其方法__init__()接受名.姓和年薪,并 将它们都存储在属性中.编写一个名为give_raise()的方法,它默认将年薪增加5000 美元,但也能够接 ...

  2. Python基础+Pythonweb+Python扩展+Python选修四大专题 超强麦子学院Python35G视频教程

    [保持在百度网盘中的, 可以在观看,嘿嘿 内容有点多,要想下载, 回复后就可以查看下载地址,资源收集不易,请好好珍惜] 下载地址:http://www.fu83.cc/ 感觉文章好,可以小手一抖 -- ...

  3. Python之路,Day4 - Python基础4 (new版)

    Python之路,Day4 - Python基础4 (new版)   本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 ...

  4. Day4 - Python基础4 迭代器、装饰器、软件开发规范

    Python之路,Day4 - Python基础4 (new版)   本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 ...

  5. python - unittest 单元测试学习

    单元测试 单元测试是用来对一个模块.一个函数或者一个类进行正确性检验的测试工作 比如对Python中的abs 的测试 输入正数: 比如 1, 2, 3, 返回值不变 输入负数: 比如 -1, -2, ...

  6. python基础系列教程——Python3.x标准模块库目录

    python基础系列教程——Python3.x标准模块库目录 文本 string:通用字符串操作 re:正则表达式操作 difflib:差异计算工具 textwrap:文本填充 unicodedata ...

  7. python基础语法(一)

    Python的特点 1. 简单 Python是一种代表简单思想的语言. 2. 易学 Python有极其简单的语法. 3. 免费.开源 Python是FLOSS(自由/开放源码软件)之一. 4. 高层语 ...

  8. Python基础语法(转)

    作者:Peter 出处:http://www.cnblogs.com/Peter-Zhang/   Python 基础语法(一) Python的特点 1. 简单 Python是一种代表简单思想的语言. ...

  9. python基础知识的学习和理解

    参考链接:https://github.com/yanhualei/about_python/tree/master/python_learning/python_base   python基础知识笔 ...

随机推荐

  1. android 4种启动模式

    在android里,有4种activity的启动模式,分别为: “standard” (默认) “singleTop” “singleTask” “singleInstance” 它们主要有如下不同: ...

  2. 关于tableView的错误提示

    WARNING: Using legacy cell layout due to delegate implementation of tableView:accessoryTypeForRowWit ...

  3. Unable to add window -- token null is not for an application

    导致报这个错是在于new AlertDialog.Builder(mcontext),虽然这里的参数是AlertDialog.Builder(Context context)但我们不能使用getApp ...

  4. bug-android之app:mergeDebugResources

    bug描述:Error:Execution failed for task ':app:mergeDebugResources'. > Crunching Cruncher seekbar_th ...

  5. Struts2中的OGNL通配符

    <action name="*_*" class="action.{1}Action" method="{2}"> 匹配,第一个 ...

  6. PyQt4多线程定时刷新控件

    1.通过事件关联和线程关联的方法刷新控件 self.listview=updatelistview()self.listview.updateText.connect(self.viewlist)   ...

  7. ubuntu安装skype

    1.添加源 sudo add-apt-repository "deb http://archive.canonical.com/ $(lsb_release -sc) partner&quo ...

  8. ganglia及ganglia-api相关介绍

    1, ganglia的安装: http://blog.topspeedsnail.com/archives/3049 2, ganglia-api项目地址 https://github.com/gua ...

  9. SqlBulkCopy 批量复制数据到数据表

    使用 SqlBulkCopy 类只能向 SQL Server 表写入数据.但是,数据源不限于 SQL Server:可以使用任何数据源,只要数据可加载到 DataTable 实例或可使用 IDataR ...

  10. struts2 学习路线

    1.请求:开发struts2流程,(常见配置.action的方法的访问.ServletApi的访问.结果页面类型) 2.强求:封装参数.类型转换.数据校验.国际化.拦截器. 3.响应页面的生成:文件上 ...