Python 单元测试 & 文档测试
1.1 单元测试
1.1.1 单元测试编写
单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。
编写一个Dict类,这个类的行为和dict一致,但是通过属性来访问。
>>> d = Dict(a=1, b=2)
>>> d['a']
1
>>> d.a
1
class dict编写如下:
[root@daidai python]# cat mydict.py
#!/usr/bin/Python
# -*- coding:utf-8 -*-
class Dict(dict):
def __init__(self, **kw):
super().__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Dict' has no attribute %s." % key)
def __setattr__(self, key, value):
self[key] = value
编写单元测试:
[root@daidai python]# cat mydict_test.py
#!/usr/bin/python
# -*- coding:utf-8 -*-
import unittest
from mydict import Dict
class TestDict(unittest.TestCase): #测试类从unittest.TestCase继承
def test_init(self): #不是以test开头的方法不被执行
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): #通过d['empty']访问不存在的key时,断言会抛出KeyError
value = d['empty']
def test_attrerror(self):
d = Dict()
with self.assertRaises(AttributeError): #通过d.empty访问不存在的key时,我们期待抛出AttributeError
value = d.empty
if __name__ == '__main__':
unittest.main() #运行单元测试
1.1.2 运行单元测试
[root@daidai python]# python mydict_test.py #加上unittest.main()运行语句
.....
----------------------------------------------------------------------
Ran 5 tests in 0.001s
OK
[root@daidai python]#
[root@daidai python]#
[root@daidai python]# python -m unittest mydict_test #不用加上unittest.main()运行语句
.....
----------------------------------------------------------------------
Ran 5 tests in 0.001s
OK
1.1.3 setUp() & tearDown()
这两个方法分别在单元测试中每个测试方法的前后被执行。
[root@daidai python]# cat mydict_test.py
#!/usr/bin/python
# -*- coding:utf-8 -*-
import unittest
from mydict import Dict
class TestDict(unittest.TestCase):
def setUp(self):
print('test begins...')
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
def tearDown(self):
print('test ends...')
#if __name__ == '__main__':
# unittest.main()
[root@daidai python]# pythonmydict_test.py #发现这样测试没有作用
[root@daidai python]# python -m unittestmydict_test
test begins...
test ends...
.test begins...
test ends...
.test begins...
test ends...
.test begins...
test ends...
.test begins...
test ends...
.
----------------------------------------------------------------------
Ran 5 tests in 0.001s
OK
1.2 文档测试
当我们编写注释时,如果写上这样的注释:
def abs(n):
'''
Function to get absolute value of number.
Example:
>>> abs(1)
1
>>> abs(-1)
1
>>> abs(0)
0
'''
return n if n >= 0 else (-n)
无疑更明确地告诉函数的调用者该函数的期望输入和输出。
并且,Python内置的“文档测试”(doctest)模块可以直接提取注释中的代码并执行测试。
doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。只有测试异常的时候,可以用...表示中间一大段烦人的输出。
让我们用doctest来测试上次编写的Dict类:
# mydict2.py
class Dict(dict):
'''
Simple dict but also support access as x.y style.
>>> d1 = Dict()
>>> d1['x'] = 100
>>> d1.x
100
>>> d1.y = 200
>>> d1['y']
200
>>> d2 = Dict(a=1, b=2, c='3')
>>> d2.c
'3'
>>> d2['empty']
Traceback (most recent call last):
...
KeyError: 'empty'
>>> d2.empty
Traceback (most recent call last):
...
AttributeError: 'Dict' object has no attribute 'empty'
'''
def __init__(self, **kw):
super(Dict, self).__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
if __name__=='__main__':
import doctest
doctest.testmod()
运行python3 mydict2.py:
$ python3 mydict2.py
什么输出也没有。这说明我们编写的doctest运行都是正确的。如果程序有问题,比如把__getattr__()方法注释掉,再运行就会报错:
$ python3 mydict2.py
**********************************************************************
File "/Users/michael/GitHub/learn-python3/samples/debug/mydict2.py",line 10, in __main__.Dict
Failed example:
d1.x
Exception raised:
Traceback (most recent call last):
...
AttributeError: 'Dict' object has no attribute 'x'
**********************************************************************
File"/Users/michael/github/learn-python3/samples/debug/mydict2.py", line16, in __main__.Dict
Failed example:
d2.c
Exception raised:
Traceback (most recent call last):
...
AttributeError: 'Dict' object has no attribute 'c'
**********************************************************************
1 items had failures:
2of 9 in __main__.Dict
***Test Failed*** 2 failures.
注意到最后3行代码。当模块正常导入时,doctest不会被执行。只有在命令行直接运行时,才执行doctest。所以,不必担心doctest会在非测试环境下执行。
相关文章