测试
测试用例
对函数 abs(),这个函数的作用就是取绝对值,我们可以编写以下几个测试用例:
- 输入正数,比如 1、 1.5、 0.99,期待返回值与输入相同
- 输入负数,比如 -1、 -1.5、 -0.99, 期待返回值与输入值相反
- 输入0, 期待返回0;
- 输入非数值类型,比如 None、 []、 {}, 期待抛出 TypeError
把上面的测试用例,放到测试模块中,就是一个完整的单元测试。
单元测试通过说明我们的函数能够正常工作,要是不过,就说明函数还有bug,
那么就得修改,直到单元测试通过。
单元测试得意义
- 一旦测试通过,以后的修改不会对abs()有影响,如果造成影响,测试就不能通过
- 单元测试,在重构中,也是经常用到的,有了单元测试,就可以放心的重构
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 如下:
import unittest
from learn.two.测试.mydict import Dict
class TestDict(unittest.TestCase):
def test_init(self):
d = Dict(a = 1, b = '测试')
self.assertEqual(d.a, 1)
self.assertEqual(d.b, '测试')
self.assertTrue(isinstance(d, dict))
# def test_key(self): #这部分是测试用例通不过的例子
# d = Dict()
# d['key'] = 'value'
# self.assertSetEqual(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
if __name__ == '__main__':
unittest.main()
直接运行 mydict_test.py
Testing started at 22:54 ...
E:\py\venv\Scripts\python.exe "D:\JetBrains\PyCharm 2018.1.1\helpers\pycharm\_jb_unittest_runner.py" --target mydict_test.TestDict
Launching unittests with arguments python -m unittest mydict_test.TestDict in E:\pyplace\learn_python3\learn\two\测试
Ran 4 tests in 0.012s
OK
Process finished with exit code 0
以上这就说明单元测试通过了
下面是测试不通过的示范(将注释的部分放开):
import unittest
from learn.two.测试.mydict import Dict
class TestDict(unittest.TestCase):
def test_init(self):
d = Dict(a = 1, b = '测试')
self.assertEqual(d.a, 1)
self.assertEqual(d.b, '测试')
self.assertTrue(isinstance(d, dict))
def test_key(self): #这部分是测试用例通不过的例子
d = Dict()
d['key'] = 'value'
self.assertSetEqual(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
if __name__ == '__main__':
unittest.main()
运行 mydict_test.py 结果:
Testing started at 22:58 ...
E:\py\venv\Scripts\python.exe "D:\JetBrains\PyCharm 2018.1.1\helpers\pycharm\_jb_unittest_runner.py" --target mydict_test.TestDict
Launching unittests with arguments python -m unittest mydict_test.TestDict in E:\pyplace\learn_python3\learn\two\测试
Ran 5 tests in 0.027s
FAILED (failures=1)
Failure
Traceback (most recent call last):
File "D:\python\Python36\lib\unittest\case.py", line 1055, in assertSetEqual
difference1 = set1.difference(set2)
AttributeError: 'str' object has no attribute 'difference'
File "D:\python\Python36\lib\unittest\case.py", line 670, in fail
raise self.failureException(msg)
AssertionError: first argument does not support set difference: 'str' object has no attribute 'difference'
可以看到,控制台输入了红色的错误日志,意味着单元测试不通过
单元测试的写法
- 需要编写一个测试类,从 unittest.TestCase 继承
- 以 test 开头的就是测试方法,不是 test 开头的不被认为是测试方法,测试的时候不被执行
- 每个类测试都需要编写 test_xxx() 方法,由于 unittest.TestCase 提供了很多内置的条件判断,我们只需要调用就可以了
常用方法
- 常用的断言就是 assertEqual();
self.assertEqual(abs(-1), 1) # 断言返回的结果与1相等
- 另一种是抛出指定类型的错误,比如 d['empty']访问不到存在的Key时,就抛出 KeyError
with self.assertRaises(KeyError):
value = d['empty']
如果通过 d.empty 访问不存在的 key 时,我们期待抛出 AttributeError:
with self.assertRaises(AttributeError):
value = d.empty
运行单元测试
- 在编写好的单元测试中,添加以下两行代码,我们就可以运行单元测试
if __name__ == '__main___':
unittest.main()
- 这样,我们就可以把 mydict_test.py 当作正常的 Python 脚本运行:
$ python mydict_test.py
总结
- 写被测试的类
- 继承 unittest.TestCase 写单元测试类
- 通过会显示绿色 Tests passed,并在输出日志中显示 OK
- 不通过显示红色 Tests failed,并在输出日志中显示 FAILD