96SEO 2026-02-20 06:44 8
接口测试是比较讲究效率的#xff0c;测试人员会希望很快能得到结果反馈#xff0c;然而接口的数量一般都很多#xff0c;而且会越来越…近期准备优先做接口测试的覆盖为此需要开发一个测试框架经过思考这次依然想做点儿不一样的东西。

接口测试是比较讲究效率的测试人员会希望很快能得到结果反馈然而接口的数量一般都很多而且会越来越多所以提高执行效率很有必要接口测试的用例其实也可以用来兼做简单的压力测试而压力测试需要并发接口测试的用例有很多重复的东西测试人员应该只需要关注接口测试的设计这些重复劳动最好自动化来做pytest和allure太好用了新框架要集成它们接口测试的用例应该尽量简洁最好用yaml这样数据能直接映射为请求数据写起用例来跟做填空题一样便于向没有自动化经验的成员推广
加上我对Python的协程很感兴趣也学了一段时间一直希望学以致用所以http请求我决定用aiohttp来实现。
但是pytest是不支持事件循环的如果想把它们结合还需要一番功夫。
于是继续思考思考的结果是其实我可以把整个事情分为两部分。
第一部分读取yaml测试用例http请求测试接口收集测试数据。
第二部分根据测试数据动态生成pytest认可的测试用例然后执行生成测试报告。
这样一来两者就能完美结合了也完美符合我所做的设想。
想法既定接着
一份简单的用例模板我是这样设计的这样的好处是参数名和aiohttp.ClientSession().request(method,url,**kwargs)是直接对应上的我可以不费力气的直接传给请求方法避免各种转换简洁优雅表达力又强。
True异步读取文件可以使用aiofiles这个第三方库yaml_load是一个协程可以保证主进程读取yaml测试用例时不被阻塞通过await
file):异步读取yaml文件并转义其中的特殊值:param
re.compile(r^\${([A-Za-z_]\w*\(.*\))}$)pattern_function2
my_iter(data):递归测试用例根据不同数据类型做相应处理将模板语法转化为正常值:param
pattern_function2.match(data)if
pattern_function3.match(data)if
bxmat.default_values.get(K).get(k)return
BXMDict(data)可以看到测试用例还支持一定的模板语法如${function}、$(a:b)等这能在很大程度上拓展测试人员用例编写的能力
http请求可以直接用aiohttp.ClientSession().request(method,url,**kwargs)http也是一个协程可以保证网络请求时不被阻塞通过await
kwargs中加入tokenkwargs.setdefault(headers,
response_handler(response)return
协程的并发真的很快这里为了避免服务响应不过来导致熔断可以引入asyncio.Semaphore(num)来控制并发
在CookieJar的update_cookies方法中如果unsafeFalse并且访问的是IP地址客户端是不会更新cookie信息#
所以这里使用的cookie_jar参数使用手动生成的CookieJar对象并将其unsafe设置为Trueasync
cookie_jarCookieJar(unsafeTrue),
case_nametest_case)res.setdefault(data.pop(case_dir),
BXMList()).append(data)else:for
case_nametest_case)res.setdefault(data.pop(case_dir),
case_name):一份测试用例执行的全过程包括读取.yml测试用例执行http请求返回请求结果所有操作都是异步非阻塞的:param
用例来对结果进行了分类这为接下来的自动生成pytest认可的测试用例打下了良好的基础
main(test_cases):事件循环主函数负责所有接口请求的执行:param
asyncio.get_event_loop()semaphore
asyncio.Semaphore(bxmat.semaphore)#
[asyncio.ensure_future(one(case_nametest_case,
loop.create_task(entrace(test_cases,
loop.run_until_complete(asyncio.ga***r(*tasks))loop.run_until_complete(task)finally:loop.close()return
首先说明下pytest的运行机制pytest首先会在当前下找test开头或结尾的.py文件如果找到了如果找到了再分析fixture如果有session或module类型的并且参数autotestTrue或标记了pytest.mark.usefixtures(a...)则先运行它们再去依次找类、方法等规则类似。
大概就是这样一个过程。
可以看出pytest测试运行起来的关键是必须有至少一个被pytest发现机制认可的testxx.py文件文件中有TestxxClass类类中至少有一个def
现在并没有任何pytest认可的测试文件所以我的想法是先创建一个引导型的测试文件它负责让pytest动起来。
可以用pytest.skip()让其中的测试方法跳过。
然后我们的目标是在pytest动起来之后怎么动态生成用例然后发现这些用例执行这些用例生成测试报告一气呵成。
test_start(self):pytest.skip(此为测试启动方法,
不执行)我想到的是通过fixture因为fixture有setup的能力这样我通过定义一个scope为session的fixture然后在TestStarter上面标记use就可以在导入TestStarter之前预先处理一些事情那么我把生成用例的操作放在这个fixture里就能完成目标了。
pytestpytest.mark.usefixtures(te,
test_start(self):pytest.skip(此为测试启动方法,
不执行)pytest有个--rootdir参数该fixture的核心目的就是通过--rootdir获取到目标创建一份testxx.py的测试文件文件内容就是content变量的内容然后把这些参数再传给pytest.main()方法执行测试用例的测试也就是在pytest内部再运行了一个pytest最后把生成的测试文件删除。
注意该fixture要定义在conftest.py里面因为pytest对于conftest中定义的内容有自发现能力不需要额外导入。
test_cases(request):测试用例生成处理:param
request.config.getoption(--rootdir)test_file
request.config.getoption(--tf)env
request.config.getoption(--te)cases
files:cases.extend([os.path.join(root,
CaseMetaClassallure.feature({}接口测试({}项目))
metaclassCaseMetaClass):test_cases_data
os.path.basename(root)project_name
os.path.basename(os.path.dirname(root))test_case_file
test_{}.py.format(case_name))with
fw:fw.write(content.format(case_name,
data.get(root)))test_cases_files.append(test_case_file)if
os.path.dirname(test_file)py_file
test_{}.py.format(os.path.basename(temp)))else:py_file
varpytest.main([-v,py_file,--alluredir,report,--te,env,--capture,no,--disable-warnings,])for
test_cases_files:os.remove(file)return
test_cases_files可以看到测试文件中有一个TestxxAPI的类它只有一个test_cases_data属性并没有testxx方法所以还不是被pytest认可的测试用例根本运行不起来。
那么它是怎么解决这个问题的呢答案就是CaseMetaClass。
allure.step(response.pop(case_name)):validator(response,validata)class
CaseMetaClass(type):根据接口调用的结果自动生成测试用例def
gen_function(function_express.format(function_name),namespace{validator:
allure.story({}.format(api.replace(_,
/)))(function)attrs[function_name]
pytest.mark.parametrize(response,validata,
test_data)(story_function)return
attrs)CaseMetaClass是一个元类它读取test_cases_data属性的内容然后动态生成方法对象每一个接口都是单独一个方法在相继被allure的细粒度测试报告功能和pytest提供的参数化测试功能装饰后把该方法对象赋值给testapi的类属性也就是说TestxxAPI在生成之后便有了若干testxx的方法此时内部再运行起pytestpytest也就能发现这些用例并执行了。
函数作用域默认设置为builtins.__dict__并合并namespace的变量:param
foobar:return:builtins.__dict__.update(namespace)module_code
types.FunctionType(function_code,
builtins.__dict__)在生成方法对象时要注意namespace的问题最好默认传builtins.__dict__然后自定义的方法通过namespace参数传进去。
至此框架的核心功能已经完成了经过几个项目的实践效果完全超过预期写起用例来不要太爽运行起来不要太快测试报告也整的明明白白漂漂亮亮的但我发现还是有些累为什么呢
我目前做接口测试的流程是如果项目集成了swagger通过swagger去获取接口信息根据这些接口信息来手工起项目创建用例。
这个过程很重复很繁琐因为我们的用例模板已经大致固定了其实用例之间就是一些参数比如目录、用例名称、method等等的区别那么这个过程我觉得完全可以自动化。
因为swagger有个网页啊我可以去提取关键信息来自动创建.yml测试文件就像搭起架子一样待项目架子生成后我再去设计用例填传参就可以了。
于是我试着去解析请求swagger首页得到的HTML然后失望的是并没有实际数据后来猜想应该是用了ajax打开浏览器控制台的时我发现了api-docs的请求一看果然是json数据那么问题就简单了网页分析都不用了。
{caseName}{data_or_params}:{data}
project_name):根据swagger返回的json数据自动生成yml测试用例模板:param
os.path.exists(project_):os.mkdir(project_)for
os.path.exists(dirs):os.mkdir(dirs)os.chdir(dirs)if
_v.get(description)data_or_params
fw:fw.write(template.format(methodmethod,apiapi,caseNamecaseName,data_or_paramsdata_or_params,datadata_s))os.chdir(project_)现在要开始一个项目的接口测试覆盖只要该项目集成了swagger就能秒生成项目架子测试人员只需要专心设计接口测试用例即可我觉得对于测试团队的推广使用是很有意义的也更方便了我这样的懒人。
【整整200集】超超超详细的Python接口自动化测试进阶教程合集真实模拟企业项目实战
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback