unittest
单元测试, 即对软件设计的最小单元进行内部逻辑、语法、算法、功能等的正解性进行验证.
References: python unittest 使用 Python Mock 类进行单元测试
测试级别:
代码级别
接口测试
数据结构测试
边界测试
模块功能级别
黑盒测试
其他
性能
代码规范等
测试过程:
初始用法 (单个测试用例)
# -*- coding: utf-8 -*-
import unittest
class Add(object):
def add(self, x, y):
return x + y
class TestAdd(unittest.TestCase):
def setUp(self):
# 构造
self.obj = Add()
def runTest(self):
print self.obj.add(10, 20) == 30
def test_add(self):
print self.obj.add(10, 20) == 30
def tearDown(self):
# 析构
self.obj = None
if __name__ == '__main__':
# demo_add = TestAdd() # 默认执行 runTest
demo_add = TestAdd('test_add') # 执行参数的方法
demo_add.run()
中级用法 (测试集)
unittest.TestSuite: 测试用例的集合, 存放测试用例的容器
添加测试集的方法:
__init__
addTest(self, test)
addTests(self, tests)
运行测试集: TextTestRunner()
简单测试集
# -*- coding: utf-8 -*-
import unittest
class Count(object):
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
class TestCount(unittest.TestCase):
def setUp(self):
# 构造
self.obj = Count()
def test_add(self):
print self.obj.add(10, 20) == 30
def test_sub(self):
print self.obj.sub(10, 5) == 5
def tearDown(self):
# 析构
self.obj = None
def get_suite():
demo_count_add = TestCount('test_add')
demo_count_sub = TestCount('test_sub')
suite = unittest.TestSuite()
suite.addTests([demo_count_add, demo_count_sub])
return suite
if __name__ == '__main__':
s = get_suite()
print s.countTestCases()
runner = unittest.TextTestRunner()
runner.run(s)
结合 map
# -*- coding: utf-8 -*-
import unittest
class Count(object):
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
class TestCount(unittest.TestCase):
def setUp(self):
# 构造
self.obj = Count()
def test_add(self):
print self.obj.add(10, 20) == 30
def test_sub(self):
print self.obj.sub(10, 5) == 10
def tearDown(self):
# 析构
self.obj = None
def get_suite():
case_list = ['test_add', 'test_sub']
demos = map(TestCount, case_list)
suite = unittest.TestSuite()
suite.addTests(demos)
return suite
if __name__ == '__main__':
s = get_suite()
print s.countTestCases()
runner = unittest.TextTestRunner()
runner.run(s)
使用 __init__
# -*- coding: utf-8 -*-
import unittest
class Count(object):
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
class TestCount(unittest.TestCase):
def setUp(self):
# 构造
self.obj = Count()
def test_add(self):
print self.obj.add(10, 20) == 30
def test_sub(self):
print self.obj.sub(10, 5) == 10
def tearDown(self):
# 析构
self.obj = None
class CountTestSuite(unittest.TestSuite):
def __init__(self):
case_list = ['test_add', 'test_sub']
demos = map(TestCount, case_list)
super(CountTestSuite, self).__init__(demos)
if __name__ == '__main__':
s = CountTestSuite()
print s.countTestCases()
runner = unittest.TextTestRunner()
runner.run(s)
自动构建测试集
unitest.makeSuite
测试方法必须以 规定前缀 开头 (前缀可以通过 makeSuite 的 prefix 参数指定, 默认是 test)
# -*- coding: utf-8 -*-
import unittest
class Count(object):
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
class TestCount(unittest.TestCase):
def setUp(self):
# 构造
self.obj = Count()
def test_add(self):
print self.obj.add(10, 20) == 30
def test_sub(self):
print self.obj.sub(10, 5) == 12
def tearDown(self):
# 析构
self.obj = None
if __name__ == '__main__':
s = unittest.makeSuite(TestCount, prefix='test')
print s.countTestCases()
runner = unittest.TextTestRunner()
runner.run(s)
高级用法
unittest.main()
自动检测测试类中所有以 test 开头的方法
使用这种方法时, 如果使用 IDLE 的话, 可能会出现下面这种错:
Traceback (most recent call last):
File "C:\Users\chaoqun.zhu\Desktop\ss.py", line 32, in <module>
unittest.main()
File "C:\Python27\lib\unittest\main.py", line 95, in __init__
self.runTests()
File "C:\Python27\lib\unittest\main.py", line 231, in runTests
sys.exit(not self.result.wasSuccessful())
SystemExit: False
这是一个 IDLE 问题
因为 unittest.main()
函数会调用 sys.exit()
来结束函数进程, 类似 sys.exit(1)
表示非正常退出, sys.exist(0)
表示正常退出;
可以使用 unittest.main(exit=False)
解决.
main() 方法过程:
结果判断
继承 unittest.TestCase
就会继承下面这些方法
# -*- coding: utf-8 -*-
import unittest
class Count(object):
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
class TestCount(unittest.TestCase):
def setUp(self):
# 构造
self.obj = Count()
def test_add(self):
self.assertEqual(self.obj.add(10, 20), 0)
def test_sub(self):
self.assertEqual(self.obj.sub(10, 5), 5)
def tearDown(self):
# 析构
self.obj = None
if __name__ == '__main__':
unittest.main(exit=False)
执行结果:
F.
======================================================================
FAIL: test_add (__main__.TestCount)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\chaoqun.zhu\Desktop\ss.py", line 21, in test_add
self.assertEqual(self.obj.add(10, 20), 0)
AssertionError: 30 != 0
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (failures=1)
第一行的 F 表示有几个 FAIL, 这里只有一个.
忽略测试
@unittest.skip(reson)
@unittest.skip(condition, reason)
@unittest.skipUnless(condition, reason)
@unittest.expectedFailure 失败不计入失败结果
@unittest.skip('Not Test')
def test_sub(self):
self.assertEqual(self.obj.sub(10, 5), 5)
@unittest.expectedFailure
def test_sub(self):
self.assertEqual(self.obj.sub(10, 5), 5)
解决环境依赖 mock
向测试对象提供一套和测试资源完全相同的接口和方法, 不关心具体实现过程, 只关心具体结果.
py 3.0 +
unittest.mock
py 2.7<br>
pip install mock
mock.Mock
关于 mock 参考: 使用 Python Mock 类进行单元测试
Last updated