需求
假设领导让你开发一个接口测试框架。领导提出了一些新的需求,你如何实现?
Unittest测试框架基础
Unittest测试框架介绍
Unittest是Python自带的测试框架,提供基础的用例管理和测试控制功能,使用灵活易于定制。Unittest中主要包含TestCase测试用例、TestSuite测试套件、测试准备及清理方法和TestRunner测试运行器等主要概念,另外还包含TestLoader用于批量加载用例生成测试套件,TestResult用于在TestRunner中记录测试结果。
Unittest测试框架使用
基础使用
编写用例
test_demo1.py
import requests
import unittest
class TestDemo(unittest.TestCase):
def setUp(self):
self.session = requests.session()
def tearDown(self):
self.session.close()
def test_get(self):
"""测试Get接口"""
url = 'https://postman-echo.com/get?a=1&b=2'
res = self.session.get(url)
self.assertDictEqual({'a': 1, 'b': 2}, res.json()['args'])
运行方法
$ python3 –m unittest test_demo1.py -vvv
自定义测试套件运行方法
loader = unittest.TestLoader()
suite = loader.discover('.testcases')
runner = unittest.TextTestRunner()
result = runner.run(suite)
测试用例的生命周期
- setUp()方法在每个测试方法执行之前调用,用于准备测试环境。
- tearDown()方法在每个测试方法执行之后调用,用于清理测试环境。
- setUpClass()方法在测试类中的所有测试方法执行之前调用,用于准备测试环境。
- tearDownClass()方法在测试类中的所有测试方法执行之后调用,用于清理测试环境。
测试用例的组织和管理
- 可以使用TestSuite类来组织多个测试用例。
- 可以使用TestLoader类来动态加载测试用例。
- 可以使用TestResult类来收集测试结果和生成测试报告。
跳过用例及期望失败
待补充
ddt数据驱动
安装ddt
$ pip install ddt
使用方法
待补充
ddt与unittest subtests的区别
- subtests: 一个测试用例,循环测试失败不中断测试
- ddt: 生成多个测试用例
ddt数据驱动原理
- @ddt.data(): 为测试函数添加数据属性
- @ddt.ddt: 遍历测试类中所有带数据属性的测试函数,动态在类中添加添加多个测试函数,并赋予数据
Unittest测试框架原理
Unittest测试框架的的原理是将继承unittest.TestCase的测试类中,所有的test开头的测试函数,生成该测试类的一个对象,然后组装成测试套件,使用测试运行器(TestRunner)运行并使用测试结果(TestResult)对象纪录每个用例的运行状态。
import unittest
class TestDemo(unittest.TestCase):
def test_1(): ...
def test_2(): ...
def test_3(): ...
# 运行方法
loader = unittest.TestLoader()
# 生成测试套件-将test_1,、test_2、 test_3生成TestDemo的对象,添加到测试套件中
suite = loader.loadTestsFromTestCase(TestDemo)
for test in suite:
print(test.id())
runner = unittest.TextTestRunner()
result = runner.run(suite)
Unittest测试框架基本结构
- TestCase :测试用例
- TestSuite:测试套件
- TestLoader:测试用例加载器
- TestResult:测试结果记录器
- TestRunner:测试运行器
TestCase类
常用方法
- setUp():需用户实现,单条测试用例准备方法
- tearDown():需用户实现,单条测试用例清理方法
- setUpClass():需用户实现,测试类准备方法
- tearDownClass():需用户实现,测试类清理方法
- run(result=None):用例运行
- debug():用例调试
- skipTest(reason):跳过用例(抛出SkipTest异常)
- countTestCases():用例数量,固定为1
常用断言方法
TestSuite类
常用方法
- addTest(test):添加单个用例对象到该测试套件
- addTests(tests):添加多个测试用例对象到该测试套件
- run(result):测试套件运行
- countTestCases():测试套件中测用例数量
__iter__()
:支持for ... in ...遍历其中所有的测试用例
TestLoader类
常用方法
- loadTestsFromTestCase(testCaseClass):通过测试类对象加载其中的所有测试函数,生成测试套件
- loadTestsFromModule(module, pattern=None):通过测试模块加载其中的所有测试用例,生成测试套件
- loadTestsFromName(name, module=None):通过字符串格式的测试函数导入路径名,如test_demo.TestDemo.test_a来加载测试用例,生成测试套件
- loadTestsFromNames(names, module=None):通过测试函数导入路径名,批量加载测试用例,生成测试套件
- getTestCaseNames(testCaseClass):通过测试类获取其中所有测试函数的测试函数导入路径名,生成测试套件
- discover(start_dir, pattern='test.py', top_level_dir=None):递归遍历目录,搜集所有test.py中的Test开头的测试类中的所有测试函数,生成测试套件
TestResult类
常用方法
- wasSuccessful():是否全部成功
- stop():停止当前测试运行
- startTest(test):开始(纪录)测试某用例
- stopTest(test):停止(纪录)测试某用例
- startTestRun():开始(纪录)整体的测试运行
- stopTestRun():停止(纪录)整体的测试运行
- addError(test, err):纪录异常用例
- addFailure(test, err):纪录失败的用例
- addSuccess(test):纪录成功的用例(默认什么都不做)
- addSkip(test, reason):纪录跳过的测试用例
- addExpectedFailure(test, err):纪录期望失败的测试用例
- addUnexpectedSuccess(test):纪录非预期成功的测试用例
- addSubTest(test, subtest, outcome):纪录子测试
TextTestRunner类
_makeResult()
:创建TestResult对象- run(test):运行测试套件
Unittest测试框架进阶
使用装饰器为测试函数添加额外属性
class TestCalc(TestCase):
@test(title='测试加法', priority='p2', status='ready', owner='superhin', iteration='v1.0.0')
def test_add(self):
self.logger.info('测试1+1=2')
self.assertEqual(1 + 1, 2)
使用元类-自动拷贝测试函数属性到测试用例对象
使用用例类属性设置通用属性
class TestDemo(TestCase):
priority = 'p1'
status = 'ready'
owner = 'superhin'
iteration = 'v0.1.0'
@test(title='test demo a', priority='p2')
def test_a(self):
self.logger.info('a demo test case')
@test(title='test ddt with data',data=['a', 'b', 'c'])
def test_b(self, item):
self.logger.info('item =', item)
测试计划-通过属性筛选测试用例
class TestPlanDemo(TestPlan):
tests = [
"test_demo.TestDemo.test_a"
]
filter = {
"status": ["ready"]
}