接口自动化允许测试人员提前介入脚本编写,从而缩短测试周期,能有效降低回归成本、用例执行成本,还可实现线上定时巡检功能等,在实际工作中具有非常大的应用价值。因此,基于以往测试经验,总结了使用unittest从0到1搭建接口自动化框架的方法步骤。
step1:搭建基础框架
1. 外层目录结构
business:业务层通用方法
common:通用方法封装
logs:日志存储
data:配置存储
testCase:用例集
main:项目执行入口
step2:实现common方法
1. 实现日志生成方法,满足用例的日志输出和日志存储的方法
def case_demo(text):
"""
打印用例信息并输出对应的日志
:param text: str 控制台要输出的内容或要打印的日志文本数据
:return:
"""
formatted_time = datetime.now().strftime('%H:%M:%S:%f')[:-3] # 日志的输出时间
stack = inspect.stack()
code_path = f"{os.path.basename(stack[1].filename)}:{stack[1].lineno}" # 当前执行文件的绝对路径和执行代码行号
content = f"[CASE]{formatted_time}-{code_path} >> {text}"
print(Fore.LIGHTCYAN_EX + content)
str_time = datetime.now().strftime("%Y%m%d")
with open(file=DIR + '\\logs\\' + f'{str_time}_info.log', mode='a', encoding='utf-8') as f:
f.write(content + '\n')
2. 实现通用断言方法,满足接口返回体的断言方法
import unittest
from common.caseOutput import error
class AssertCommon(unittest.TestCase):
def code_assert(self, expect, actual):
if expect != actual:
text = f'res code different, expect code: {expect}, actual code: {actual}.'
error('assert fail! ' + text)
self.fail(text)
def __assertEqual(self):
pass
def json_assert(self, expect, actual):
"""
json通用断言方法
:param expect: 定义预期返回体
:param actual: 实际返回的json
:return: 断言成功返回None,断言失败触发fail
"""
# 字段是否存在的校验
for key, value in expect.items():
self.assertIn(key, actual.keys())
# 校验是否存在多余的字段
self.assertEqual(len(expect.keys()), len(actual.keys()),
msg=f'response keys len different, response keys have: {list(actual.keys())}')
for key, value in expect.items():
# 进行数据类型的校验
if isinstance(value, type):
self.assertEqual(value, type(actual[key]),
msg=f'{key} type error! actual type is {str(type(actual[key]))}')
elif isinstance(value, list):
for i in range(len(value)):
if isinstance(value[i], type):
self.assertEqual(value[i], type(actual[key][i]),
msg=f'list element {actual[key][i]} type different, actual response {actual[key]}')
elif isinstance(value[i], dict):
self.json_assert(value[i], actual[key][i])
else:
self.assertEqual(value[i], actual[key][i],
msg=f'list element {actual[key][i]} value different, actual response {actual[key]}')
else:
self.assertEqual(value, actual[key],
msg=f'{key} value error! actual value is {str(actual[key])}')
3. 实现yaml配置读取方法,满足不同维度配置的读取,并且实现环境切换的方法
def config_load():
"""读取配置信息的方式"""
with open(file=f'{DIR}/data/envConfig/{ENVIRON}/config.yml', mode='r', encoding='utf-8') as f:
return yaml.load(f, Loader=yaml.FullLoader)
step3:main实现
1. 用例批量执行方法
使用unittest下的TestLoader、TestSuite、TextTestRunner实现用例的批量装载和执行。
import unittest
suite = unittest.TestLoader().discover('./testCase', 'test*.py')
runner = unittest.TextTestRunner()
runner.run(suite)
2. 定义全局变量
当前目录路径、环境变量等。
3. 报告的生成
常见的报告生成方法:HTML报告(HtmlTestRunner、BeautifulReport)、allure等。
4. 控制不同执行维度
用例的执行维度最好可以控制,使得测试工作在不同测试阶段更加灵活,比如冒烟测试时,更关注主流程场景的测试用例执行情况。
if __name__ == '__main__':
run_pattern = 'all' # all 全量测试用例执行 / smoking 冒烟测试执行 / 指定执行文件
if run_pattern == 'all':
pattern = 'test_*.py'
elif run_pattern == 'smoking':
pattern = 'test_major.py'
else:
pattern = run_pattern + '.py'
suite = unittest.TestLoader().discover('./testCase', pattern=pattern)
result = BeautifulReport(suite)
result.report(filename="report.html", description='测试报告', report_dir='./')
step4:转换所有主流程测试用例
实现用例的前置条件
实现用例结果的断言方法
遵循用例的编码规范:
①模块的定义,按接口拆分包,按用例级别拆分模块
②定义方法名 ,如:test01_remove_key
③用例描述,“”“XXXX”“”
④所有步骤需要通过日志中的step声明步骤过程
⑤断言方法复用common封装好的能力
step5:business实现
封装接口协议的调用方法
封装数据初始化的方法
封装数据源的断言方法
封装数据的清理方法
step6:主流程复用business的能力
setup实现数据清理方法
实现数据初始化方法和断言方法
step7:编写input测试用例
通用测试点实现参数化
非通用测试点直接输出测试用例
评论区