Python单元测试
部分内容转载自:https://www.liaoxuefeng.com
单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作
比如对函数
abs()
,我们可以编写以下几个测试用例:1.输入正数:如
1
、1.2
、0.99
,期待返回值与输入相同2.输入负数:如
-1
、-1.2
、-0.99
,期待返回值与输入相反3.输入
0
,期待返回0
4.输入非数值类型:如
None
、[]
、{}
,期待抛出TypeError
将上面的测试放到一个测试模块里,就是一个完整的单元测试
编写单元测试
例: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()
- 另一种方法是在命令行通过参数
-m unittest
直接运行单元测试:
python -m unittest myDict_test
setUp和tearDown
- 可以在单元测试中编写两个特殊的
setUp()
和tearDown()
方法。这两个方法会分别在每调用一个测试方法的前后分别被执行。 setUp()
和tearDown()
方法有什么用呢?设想你的测试需要启动一个数据库,这时,就可以在setUp()
方法中连接数据库,在tearDown()
方法中关闭数据库,这样,不必在每个测试方法中重复相同的代码:
class TestDict(unittest.TestCase):
def setUp(self):
print('setUp...')
def tearDown(self):
print('tearDown...')
可以再次运行测试看看每个测试方法调用前后是否会打印出setUp...
和tearDown...
unittest核心工作原理
unittest最核心的四个概念:
test case
:测试用例,测试当中的最小单元。unittest提供一个基本的TestCase用来创建用例test suite
:用来将需要一同执行的测试用例聚合在一起test runner
:对测试进行编排并把结果返回给用户test fixture
:代表执行一个或多个测试用例需要的准备环境以及相关联的清理环境的工作
python -m unittest -v myDict_test
:
test_0_to_60 (student_test.studentTest) ... ok
test_60_to_80 (student_test.studentTest) ... ok
test_80_to_100 (student_test.studentTest) ... ok
test_invalid (student_test.studentTest) ... ok
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK
python - m unittest -h
查看使用说明测试类、测试方法名字最好以test开头,很多工具能根据名字来自动运行
测试类里面的setUp/tearDown会在每个case执行之前/之后执行,setUpClass/tearDownClass加上
@classmethod
在整个测试类开始和结束的时候执行