@hainingwyx
2018-12-07T21:26:25.000000Z
字数 2840
阅读 1196
python
测试
单元测试,就是对一个模块,一个函数,或则是一个类进行正确性检测的一类测试工作。
单元测试不仅仅在测试的时候保障函数、模块或者类的功能符合我们的需求。同时,也有利于我们在未来修改类或者函数的时候,只需要再跑一遍单元测试就可以确保我们的修改对功能不会产生影响。
编写单元测试时,我们需要编写一个测试类,从unittest.TestCase
继承。
以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。
对每一类测试都需要编写一个test_xxx()
方法。由于unittest.TestCase
提供了很多内置的条件判断,我们只需要调用这些方法就可以断言输出是否是我们所期望的。最常用的断言就是assertEquals()
:
self.assertEquals(abs(-1), 1) # 断言函数返回的结果与1相等
另一种重要的断言就是期待抛出指定类型的Error,比如通过d['empty']
访问不存在的key时,断言会抛出KeyError
:
with self.assertRaises(KeyError):
value = d['empty']
可以在测试程序中加入:
if __name__ == '__main__':
unittest.main()
这样可以把测试程序当正常脚本运行:
$ python mydict_test.py
另一种更常见的方法是在命令行通过参数-m unittest
直接运行单元测试:
$ python -m unittest mydict_test
常用命令:
$ python -m unittest -h
可以在单元测试中编写两个特殊的setUp()
和tearDown()
方法。这两个方法会分别在每调用一个测试方法的前后分别被执行。
setUp()
和tearDown()
方法有什么用呢?设想你的测试需要启动一个数据库,这时,就可以在setUp()
方法中连接数据库,在tearDown()
方法中关闭数据库,这样,不必在每个测试方法中重复相同的代码:
class TestDict(unittest.TestCase):
def setUp(self):
print 'setUp...'
def tearDown(self):
print 'tearDown...'
setUpClass()
:一个类方法在单个类测试之前运行。setUpClass作为唯一的参数被调用时,必须使用classmethod
作为装饰器。
tearDownClass()
:一个类方法在单个类测试之后运行。setUpClass作为唯一的参数被调用时,必须使用classmethod
作为装饰器。
此外setUpModule
和tearDownModule
不再详细介绍。
业务函数, mathfunc.py
def add(a, b):
return a+b
def minus(a, b):
return a-b
def multi(a, b):
return a*b
def divide(a, b):
return a/b
测试用例, test_mathfunc.py
import unittest
from mathfunc import *
class TestMathFunc(unittest.TestCase):
# TestCase基类方法,所有case执行之前自动执行
@classmethod
def setUpClass(cls):
print("这里是所有测试用例前的准备工作")
# TestCase基类方法,所有case执行之后自动执行
@classmethod
def tearDownClass(cls):
print("这里是所有测试用例后的清理工作")
# TestCase基类方法,每次执行case前自动执行
def setUp(self):
print("这里是一个测试用例前的准备工作")
# TestCase基类方法,每次执行case后自动执行
def tearDown(self):
print("这里是一个测试用例后的清理工作")
@unittest.skip("我想临时跳过这个测试用例.")
def test_add(self):
self.assertEqual(3, add(1, 2))
self.assertNotEqual(3, add(2, 2)) # 测试业务方法add
def test_minus(self):
self.skipTest('跳过这个测试用例')
self.assertEqual(1, minus(3, 2)) # 测试业务方法minus
def test_multi(self):
self.assertEqual(6, multi(2, 3)) # 测试业务方法multi
def test_divide(self):
self.assertEqual(2, divide(6, 3)) # 测试业务方法divide
self.assertEqual(2.5, divide(5, 2))
if __name__ == '__main__':
unittest.main(verbosity=2)
注意:
skip装饰器一共有三个 unittest.skip(reason)、unittest.skipIf(condition,reason)、unittest.skipUnless(condition,reason),skip无条件跳过,skipIf当condition为True时跳过,skipUnless当condition为False时跳过。
每个测试方法均以 test 开头,否则是不被unittest识别的。
其实每一个test开头的方法都会加载为独立的测试用例。
在unittest.main()中加 verbosity 参数可以控制输出的错误报告的详细程度,默认是 1,如果设为 0,则不输出每一用例的执行结果。如果参数为2则表示输出详细结果。
单元测试可以有效地测试某个程序模块的行为,是未来重构代码的信心保证。
单元测试的测试用例要覆盖常用的输入组合、边界条件和异常。
单元测试代码要非常简单,如果测试代码太复杂,那么测试代码本身就可能有bug。
单元测试通过了并不意味着程序就没有bug了,但是不通过程序肯定有bug。
https://segmentfault.com/a/1190000008048642
https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00140137128705556022982cfd844b38d050add8565dcb9000
https://juejin.im/entry/576026f85bbb500063d67880
https://blog.csdn.net/luanpeng825485697/article/details/79459771