Python Unittest单元测试框架原理与实战指南
本文详细介绍Python标准库unittest的核心原理与使用方法。内容涵盖测试类的继承、Setup/TearDown生命周期管理、TestSuite测试集构建、多种断言方式及错误处理机制,以及如何生成TXT和HTML格式的测试报告。通过具体代码示例,帮助开发者掌握自动化测试的最佳实践。
Unittest基本使用步骤
使用Python标准库unittest进行单元测试,主要遵循以下基本步骤:
首先,需要导入unittest模块。
其次,创建一个新的类,并使其继承自unittest.TestCase基类。
接着,在该类中定义以test为前缀的函数,这些函数将作为具体的测试用例。注意,函数名必须以test开头,这是框架识别测试用例的关键规则。
在执行具体的测试用例之前,框架会自动调用setUp函数(针对每个测试用例执行一次)或者setUpClass函数(针对所有测试用例仅执行一次),用于初始化测试环境。
测试用例执行完毕后,框架会调用tearDown函数(针对每个测试用例执行多次)和tearDownClass函数(仅执行一次),用于清理测试资源。
注意事项:
1、在继承TestCase的类中,不应重写__init__()方法,以免干扰测试框架的内部机制。
2、只有以test开头的函数才会被unittest框架识别并执行,其他函数将被忽略。
3、如果需要使用setUpClass()和tearDownClass(),必须使用@classmethod装饰器进行修饰,否则框架无法正确调用。
测试生命周期与执行结果
# -*- encoding=utf-8 -*-
import unittest
class Demo1(unittest.TestCase):
def setUp(self):
print '调用 setup 函数'
@classmethod
def setUpClass(cls):
print '调用 setupClass 函数'
def tearDown(self):
print '调用 tearDown 函数'
@classmethod
def tearDownClass(cls):
print '调用 tearDownClass 函数'
@staticmethod
def test_add():
print '3 + 5 = {}'.format(3 + 5)
@staticmethod
def test_sub():
print '3 - 5 = {}'.format(3 - 5)
if __name__ == '__main__':
unittest.main()
以下是运行上述基本测试用例后的典型输出结果:
调用 setupClass 函数
调用 setup 函数
3 + 5 = 8
调用 tearDown 函数
调用 setup 函数
3 - 5 = -2
调用 tearDown 函数
调用 tearDownClass 函数
Ran 2 tests in 0.012s
OK
使用TestSuite管理测试用例
除了自动运行,还可以通过TestSuite【测试组】手动添加测试用例来进行更灵活的测试控制。
# -*- encoding=utf-8 -*-
class Class1(object):
def __init__(self):
print '调用 Class1 初始化函数'
self.name = '未定义姓名'
self.age = '未定义年龄'
def set_name(self, name):
self.name = name
def set_age(self, age):
self.age = age
def print_name(self):
print 'Class1 的姓名是:{}'.format(self.name)
def print_age(self):
print 'Class1 的年龄是:{}'.format(self.age)
if __name__ == '__main__':
pass
# -*- encoding=utf-8 -*-
import unittest
from Class1 import Class1
class CallClass1(unittest.TestCase):
def setUp(self):
self.class1 = Class1()
pass
def tearDown(self):
self.class1 = None
pass
def test_set_name(self):
self.class1.set_name('设置了名字')
self.class1.print_name()
def test_print_name(self):
self.class1.print_name()
if __name__ == '__main__':
unittest.main()
# -*- encoding=utf-8 -*-
import unittest
from Test_Demo2 import CallClass1
if __name__ == '__main__':
testSuite = unittest.TestSuite()
testSuite.addTest(CallClass1('test_set_name'))
testSuite.addTests(
[CallClass1('test_set_name'), CallClass1('test_print_name')])
textTestRunner = unittest.TextTestRunner()
textTestRunner.run(testSuite)
运行包含TestSuite的测试代码后,结果如下:
调用 Class1 初始化函数
Class1 的姓名是:设置了名字
调用 Class1 初始化函数
Class1 的姓名是:设置了名字
调用 Class1 初始化函数
Class1 的姓名是:未定义姓名
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
Process finished with exit code 0
为了便于后续分析,可以将测试结果记录到txt文件中。
生成TXT与HTML测试报告
# -*- encoding=utf-8 -*-
import unittest
from Test_Demo2 import CallClass1
if __name__ == '__main__':
testSuite = unittest.TestSuite()
testSuite.addTest(CallClass1('test_set_name'))
testSuite.addTests(
[CallClass1('test_set_name'), CallClass1('test_print_name')])
# textTestRunner = unittest.TextTestRunner()
# textTestRunner.run(testSuite)
# 将测试结果输出到测试报告中
with open('UnittestTextReport.txt', 'w') as f:
runner = unittest.TextTestRunner(stream=f, verbosity=2)
runner.run(testSuite)
此外,还可以将测试结果导出为更易读的html文件报告。
# 将测试结果输出到测试报告html中
with open('HTMLReport.html', 'w') as f:
runner = HTMLTestRunner(stream=f,
title='MathFunc Test Report',
description='generated by HTMLTestRunner.',
verbosity=2
)
runner.run(suite)
断言机制与错误处理
断言是单元测试的核心,用于验证代码行为是否符合预期。
当断言条件为真时,测试通过,并继续执行断言之后的代码(例如打印成功提示信息)。
若断言条件为假,则后续代码不再执行,并记录错误信息。在unittest的输出中,'F'代表断言失败(Failure),若捕获到程序异常,则标记为'E'(Error)。
补充说明:如果断言失败,当前测试函数(def)会立即停止运行,但框架会继续执行列表中后续的测试函数。
重要提示:切勿在try语句块中使用assert断言。因为assert失败时会抛出异常,如果将其包裹在try中,异常会被捕获,导致测试用例被错误地标记为通过,从而掩盖真实问题。
断言执行后的结果标识如下:
. 或 pass:表示测试通过。
F (False):表示断言未通过,测试失败。
E (Error):表示程序运行过程中发生了内部错误。
unittest支持自动查找当前目录下所有的测试用例(默认查找以test开头的.py文件,也可自定义配置)。
自动发现与运行测试用例
# -*- encoding=utf-8 -*-
import unittest
import os
if __name__ == '__main__':
loader = unittest.defaultTestLoader.discover(os.getcwd())
# tests = unittest.defaultTestLoader.discover(
# start_dir='.', # => 指定查找的目录
# pattern='test*.py' # => 指定查找规则
# )
runner = unittest.TextTestRunner()
runner.run(loader)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









