目录

前言:

1. 该框架重构自之前的框架

2. 目录截图

一、tox简介和使用介绍

1. tox简介

2. 配置文件tox.ini

二、框架搭建

1. 封装接口请求

2. 配置接口信息

3. 维护测试数据

4. 配置日志

5. 加载接口配置信息

6. 加载有接口依赖的接口配置信息

7. 处理接口信息中的url、params和headers

8. 获取token

9. conftest.py文件配置

10. 测试用例-不需要接口依赖

11. 测试用例-需要接口依赖

12. 执行测试用例

13. git地址

三、Jenkins任务配置


前言:

1. 该框架重构自之前的框架

Python+Requests+Pytest 接口自动化测试脚本总结

2. 目录截图

一、tox简介和使用介绍

1. tox简介

tox是一个管理测试虚拟环境的命令行工具,其核心作用是:

支持创建隔离的python环境,在里面可以安装不同版本的python解释器和各种依赖库,方便开发者做自动化测试、打包和持续集成等

2. 配置文件tox.ini

[tox]
skipsdist=True
envlist = py37-int[testenv]
basepython = python3.7
setenv = ENV = {env:ENV:sandbox}PYTHONIOENCODING = utf-8commands =# tox will not install new packages when requirements changing unless "tox -r" recreate envpip install -q -i https://mirrors.aliyun.com/pypi/simple/ -r {toxinidir}/requirements.txt# Append more arguments inside "pytest" sections with "addopts"pytest --alluredir ./allure-results {posargs}

1)[tox]下面是全局性的配置项:

"skipsdist"是指定tox在运行过程中跳过打包环节,因为项目无打包需求;

“envlist”字段定义了tox操作的环境

2)[testenv]下面是虚拟环境默认配置项:

“basepython”配置的是python解释器版本;

“setenv”设置环境变量,在项目中可以读取环境变量,从而决定运行哪个环境的配置

3)取操作系统的环境变量:

{env:ENV:sandbox},效果等同于os.environ['ENV']。在取不到环境变量时则取配置的默认值”sandbox“。该值是测试环境,比如prod代表生产环境,sandbox代表测试环境。那么配置环境变量时,可以配置”sandbox“或者”prod“作为默认值;

PYTHONIOENCODING = utf-8,配置编码方式为utf-8,防止中文乱码

4)执行命令:

“commands”后面配置构建好虚拟环境后要执行的命令。比如安装插件和生成allure的html测试报告

二、框架搭建

1. 封装接口请求

1)导入requests库,封装requests库的get()和post()方法

2)call()函数中,封装了get()和post()函数;参数多了一个method,且参数params和headers均可以不传参

3)使用raise主动抛出异常,如果接口方法不是get或者post,则抛出错误信息

# -- coding: utf-8 --import requestsdef call(url, method, params=None, headers=None):method = method.lower()if method not in ('get', 'post'):raise Exception('Invalid request method [%s], should be "get" or "post"' % method)if method == 'get':return get(url, params, headers)elif method == 'post':return post(url, params, headers)else:raise Exception('Should not run into here')def get(url, params, headers=None):resp = requests.get(url, params=params, headers=headers)return respdef post(url, params, headers=None):resp = requests.post(url, data=params, headers=headers)return resp

2. 配置接口信息

1)接口信息配置在yaml文件中。常规的接口信息数据项介绍:

financial_invest_demand:                             # 接口名称
  description: 购买产品                                  # 接口描述
  depend_on: financial_active_list                 # 接口依赖,无依赖的接口不需要该项,被依赖的接口该项值为空
  category: financial                                       # 接口参数所在路径,参数文件命名为”接口名称.json“
  method: post                                               # 接口类型
  url: /invest/                                                   # 接口url
  params:                                                        # 接口参数,也可直接维护在json文件中
    product_id:

2)skip-test: true  # 执行测试用例时,跳过该用例

3)enabled_only: sandbox  #   区分测试环境

4)disable_auth: true  # 区分是否是登录接口

5)&和*:&用来建立锚点,*用来引用锚点。

比如”&login_sandbox“就是建立一个sandbox环境登录的接口信息锚点,然后”environments“中使用”*login_sandbox“就可以直接引用”bootstrap_sandbox“中的所有数据项

6)如何自动生成接口信息?

可以使用抓包工具fiddler或者charles抓包后,生成.har文件。然后通过httprunner的har2case,将.har文件转换成yaml格式

default_params: &default_paramsskip_test: truedevice_id: XXXapp-version: 4.26.0bootstrap_sandbox: &login_sandboxdescription: 【登录】手机号skip_test: trueenabled_only: sandboxcategory: accountmethod: posturl: /login/disable_auth: trueparams:<< : *default_paramsenvironments:sandbox:endpoint: https://XXX.combootstrap:<< : *login_sandboxprod:endpoint: https://XXX.combootstrap:<< : *login_prodheaders:Authorization: Basic XXXstage:endpoint: https://XXX.cnlogin_with_mobile:<< : *login_sandboxfinancial_main:description: 首页method: geturl: /main/financial_invest:description: 购买产品depend_on: financial_active_listcategory: financialmethod: posturl: /invest/params:product_id:1sort_order: -1limit:financial_active_list:description: 产品列表depend_on:category: financialmethod: geturl:  /list/

3. 维护测试数据

1)某些get和post接口中,需要params参数。可以把params维护在yaml配置文件中,也可以单独维护在json文件中

2)每个需要参数的接口维护一个json文件。测试数据存在list里,且以dict形式存储。一个list里可以有多个dict,即可以有多组测试数据。比如登录接口,可以维护两组数据:邮箱账号和手机账号

[{"params": {"product_id": "1","sort_order": -1,"limit": ""}
}
]

3)json文件路径,fixtures+测试环境+category(接口分类)+接口名称.json

举例说明:fixtures+sandbox+financial+financial_invest_demand.json

4. 配置日志

1)使用python中的 logging.config.dictConfig 函数配置日志

2)使用命令:tox > log_name.log  把测试用例的运行结果,输出到日志文件中

import logging.configlogging.config.dictConfig({"version": 1,"disable_existing_loggers": False,"root": {"level": "DEBUG", "handlers": ["console"]},"formatters": {"verbose": {"format": "%(levelname)s %(asctime)s %(pathname)s#%(lineno)d:\n %(message)s"},"concise": {"format": "%(levelname)s %(asctime)s %(message)s"},"lean": {"format": "%(asctime)s: %(message)s"},},"handlers": {"console": {"level": "DEBUG","class": "logging.StreamHandler","formatter": "lean",},},}
)

5. 加载接口配置信息

1)在函数 _load_api_dsl() 内定义三个全局变量,_env, _api_descriptor, _all_testcases

2)_env 是个字典(dict),存储metadata/api.yml中配置的测试环境所对应的登录接口信息;

_api_descriptor  是个dict,存储api.yml中接口信息,除了跳过(skip_test=true)、带有依赖(存在depend_on)和环境配置(environments)的接口信息;

_all_testcases 是个元组(tuple),里面嵌套tuple,存储接口名称(api_name)和描述(description)

_env = None
_api_descriptor = None
_all_testcases = None# 加载接口配置信息(metadata/api.yml)
def _load_api_dsl(env):global _env, _api_descriptor, _all_testcasesapi_dsl = os.path.join('metadata', 'api.yml')with open(api_dsl, 'r', encoding='utf-8') as f:dsl = yaml.full_load(f)  # dsl是dict类型,存储的是api.yml中所有的接口信息_env = dsl['environments'][env]  # 运行环境相对应的登录接口信息del dsl['environments']_api_descriptor = dict()  # 存储api.yml中接口信息testcases = list()  # 存储接口名称(api_name)和描述(description)for key, api_dsl in dsl.items():if ('skip_test' in api_dsl and api_dsl['skip_test']) or ('depend_on' in api_dsl):continuedesc = api_dsl['description'] if 'description' in api_dsl else ''testcases.append((key, desc, ),)_api_descriptor[key] = api_dsl_all_testcases = tuple(testcases)

6. 加载有接口依赖的接口配置信息

1)在函数 _load_api_dsl_depend() 内定义三个全局变量,_env, _api_descriptor, _all_testcases

2)_env 是个字典(dict),存储metadata/api.yml中配置的测试环境所对应的登录接口信息;

_api_descriptor_depend 是个dict,存储带有依赖(存在depend_on)的接口信息;

_all_testcases_depend 是个元组(tuple),里面嵌套tuple,存储带有依赖的接口名称(api_name)和描述(description)

def _load_api_dsl_depend(env):global _env, _api_descriptor_depend, _all_testcases_dependapi_dsl = os.path.join('metadata', 'api.yml')with open(api_dsl, 'r', encoding='utf-8') as f:dsl = yaml.full_load(f)  # dsl是dict类型,存储的是api.yml中所有的接口信息_env = dsl['environments'][env]  # 运行环境相对应的登录接口信息,参数env可选项包括:sandbox,prod和stage(在tox.ini中配置)del dsl['environments']_api_descriptor_depend = dict()  # 存储api.yml中接口信息,除了跳过(skip_test)和环境配置(environments)的信息testcases = list()  # 存储接口名称(api_name)和描述(description)for key, api_dsl in dsl.items():if 'depend_on' not in api_dsl:continuedesc = api_dsl['description'] if 'description' in api_dsl else ''testcases.append((key, desc, ),)_api_descriptor_depend[key] = api_dsl_all_testcases_depend = tuple(testcases)

7. 处理接口信息中的url、params和headers

1)设置环境变量:os.environ['ENV'] = 'sandbox'  ,对应配置文件tox.ini中的环境配置 ENV = {env:ENV:sandbox}

2)获取环境变量:os.getenv('ENV')

3)   url:除了登录接口中,其他接口的url均未包含endpoint(即https://aa.bb.com),所以需要拼接

4)params:先从配置文件中获取参数,再从测试数据文件中获取参数。update()方法可更新字典的键值对。比如登录接口的账号和密码,如果不想维护到配置文件中,可以维护在测试数据文件中

5)headers:  同params,除了登录接口,其他接口均需要token值,token值来源于登录接口

def resolve(name, dsl):env = os.getenv('ENV', None)endpoint = _env['endpoint']  # 运行环境的urlenable_only = _env['bootstrap']['enabled_only'] if 'enabled_only' in dsl else Noneif enable_only and enable_only != env:  # 如果api.yml中的环境与tox.ini中环境不一致,则返回return Noneurl = '%s%s' % (_env['endpoint'], dsl['url'])  # 拼接完整的接口urlcategory = dsl['category'] if 'category' in dsl else ''  # 接口类型,在接口配置文件中维护该参数path_comp = [_project_root, 'fixtures', env, ]if category:path_comp.append(category)path_comp.append('%s.json' % name)  # "fixtures/测试环境"下的json文件,命名规范是"api_name.json"fixture_file = os.path.join(*path_comp)  # 拼接测试数据的文件路径api = {'url': url,'method': dsl['method'],'params': dict(),'headers': dict(),}if 'headers' in dsl:api['headers'].update(dsl['headers'])if 'params' in dsl:api['params'].update(dsl['params'])disable_auth = dsl['disable_auth'] if 'disable_auth' in dsl else Falseif not disable_auth:  # 处理非登录接口的headersglobal _access_tokenapi['headers']['Authorization'] = 'Bearer %s' % _access_tokenapis = []if not os.path.exists(fixture_file):apis.append(api)else:  # 处理存在测试数据的接口with open(fixture_file, encoding='utf-8') as f:fixtures = json.load(f)if isinstance(fixtures, dict):fixtures = [fixtures]for fixture in fixtures:# api_copy = api.copy()api_copy = copy.deepcopy(api)if 'headers' in fixture:api_copy['headers'].update(fixture['headers'])if 'params' in fixture:api_copy['params'].update(fixture['params'])apis.append(api_copy)return apis

8. 获取token

1)上面有提到,_env存储的是当前运行环境下的登录接口信息

2)发送登录接口请求后,用全局变量 _access_token 存储token的值,供其他接口使用

def _bootstrap(env):global _envapi_dsl = _env['bootstrap']  # 运行环境相对应的登录接口信息api_dsl = resolve('bootstrap', api_dsl)api_dsl = api_dsl[0]resp = api.call(api_dsl['url'], api_dsl['method'], api_dsl['params'], api_dsl['headers'])if resp.status_code == 200:result = resp.json()  # 相当于json.loads(resp.text)if result['success'] == True:global _access_token_access_token = result['access_token']returnraise Exception('Login failed')

9. conftest.py文件配置

1)该文件是Pytest框架中的文件,名字是固定的;作用是:给测试用例提供前置准备工作和后置清理工作

2)该项目的前置工作(setup()函数):加载接口配置信息(包括需要和不需要接口依赖的接口)、登录后获取token

import settingsdef pytest_sessionstart(session):settings.setup()
def setup():global _all_testcases, _api_descriptorif _all_testcases:returnenv = os.getenv('ENV', None)if not env or env not in ('stage', 'sandbox', 'prod', ):raise Exception('Environment is not configured. Sould be stage, sandbox, or prod.')_load_api_dsl(env)  # 加载接口配置信息(metadata/api.yml)_load_api_dsl_depend(env)_bootstrap(env)  # 登录后,获取access_token

10. 测试用例-不需要接口依赖

1)使用pytest.mark.parametrize装饰器实现用例参数化,里面写两个参数

2)第一个参数是一个字符串,里面有两个参数,api_name(接口名称)和description(描述)

3)第二个参数是一个列表,里面的数据是元组类型。类似这样[('api_name1','description1'),('api_name2','description2'),...]

4)lookup()函数返回的是接口配置文件中不带依赖的api_name下的接口信息

# -- coding: utf-8 --import loggingimport pytestimport api
import settings@pytest.mark.parametrize('api_name, description',[case for case in settings.list_testcases()])
def test_all(api_name, description):api_dsl = settings.lookup(api_name)requests = settings.resolve(api_name, api_dsl)for req in requests:resp = api.call(req['url'], req['method'], req['params'], req['headers'])result = resp.json()#logging.debug(resp.text)assert resp.status_code == 200if result['success'] == False:logging.debug(resp.text)assert result['success']result = result['result']if 'expect' in api_dsl:expectations = api_dsl['expect']_evaluate(result, expectations)
def lookup(api_name):global _api_descriptorreturn _api_descriptor[api_name]

11. 测试用例-需要接口依赖

# 购买售卖中的产品(依赖产品列表中是否存在产品,如果存在,则购买某产品)
@pytest.mark.dependency(depends=["get_demand_list"])
@pytest.mark.parametrize('api_name', ['financial_invest_demand'])
def test_financial_invest_demand(api_name):api_dsl = settings.lookup_depend(api_name)depend_on_name = api_dsl['depend_on']# 取依赖的接口depend_api_dsl = settings.lookup_depend(depend_on_name)depend_requests = settings.resolve(depend_on_name, depend_api_dsl)requests = depend_requestsreq = requests[0]# 取出product_idresp_depend = api.call(req['url'], req['method'], req['params'], req['headers'])result_depend = resp_depend.json()product_id = result_depend["result"]['products'][0]["id"]# 替换参数requests = settings.resolve(api_name, api_dsl)req = requests[0]req['params'].update({"product_id": product_id,})resp = api.call(req['url'], req['method'], req['params'], req['headers'])result = resp.json()assert resp.status_code == 200if result['success'] == False:logging.debug(resp.text)assert result['success']

12. 执行测试用例

1)进入项目根目录后,执行命令:tox,相当于tox sandbox。即如果tox后面不加测试环境名称,则使用tox.ini中默认配置[testenv]中配置的环境sandbox;

默认执行的是pytest管理的全部的用例文件。tox + 测试用例文件相对路径,可指定执行某个用例文件

2)执行命令:tox -e sandbox或者tox -e prod,则可分别指定执行环境sandbox和prod下的测试用例。但是需要在配置文件tox.ini中添加如下配置信息

[testenv:sandbox]
setenv =ENV = {env:ENV:sandbox}PYTHONIOENCODING = utf-8[testenv:prod]
setenv =ENV = {env:ENV:prod}PYTHONIOENCODING = utf-8

13. git地址

https://github.com/ChangYixue/api-test.git

三、Jenkins任务配置

1. Description:对构建任务的描述

2. Discard old builds:丢弃旧的构建,设置”保持构建的天数“和”保持构建的最大个数“

3. This project is parameterized:设置参数,添加字符串类型参数。参数添加成功后,构建时可以输入参数

4. Source Code Management:源码管理,配置github的url和凭证

5. Build Triggers:构建任务的触发器

在Authentication Token中指定TOKEN_NAME,然后可以通过连接JENKINS_URL/job/JOBNAME/build?token=TOKEN_NAME来启动build

6. Build-Execute shell:构建前执行shell命令

7. Post-build Actions:构建后操作,生成测试报告

8. E-mail Notification:构建后发送邮件到指定的邮箱

Python+Pytest+tox 接口自动化测试框架相关推荐

  1. 2023最新pytest+yaml接口自动化测试框架封装总结

    1. 框架封装基础 以下是框架封装的技术基础,打好这些基础的话,能够很轻松地封装出来框架 对于基础还有欠缺的话,建议针对性精进: 1. 扎实的Python语言基础 函数.类 文件读写 处理报错 数据结 ...

  2. 基于pytest搭建接口自动化测试框架,提供源码

    基于pytest搭建接口自动化测试框架 框架整体介绍和方法教程 新框架(比这个功能多了很多,用例使用yaml编写) 源码框架结构 xmind项目结构介绍 源码地址 使用教程 1.全局变量设置和使用 2 ...

  3. python接口测试_Python接口自动化测试框架实战开发(一)

    目录 一丶叙述 二丶接口基础知识 三丶接口测试工具 四丶Fiddler的使用 五丶unittest使用 六丶mock服务入门到实战 七丶接口自动化框架设计到开发 一丶叙述 1.项目介绍 整个项目分为四 ...

  4. Python+unittest+requests 接口自动化测试框架搭建 完整的框架搭建过程 实战

    一.Python+unittest+requests+HTMLTestRunner 完整的接口自动化测试框架搭建_00--框架结构简解 首先配置好开发环境,下载安装Python并下载安装pycharm ...

  5. 用robot framework + python实现http接口自动化测试框架

    前言 下周即将展开一个http接口测试的需求,刚刚完成的java类接口测试工作中,由于之前犯懒,没有提前搭建好自动化回归测试框架,以至于后期rd每修改一个bug,经常导致之前没有问题的case又产生了 ...

  6. u3d 模版测试 失败_基于Python的HTTP接口自动化测试框架实现

    一.测试需求描述 对服务后台一系列的http接口功能测试. 输入:根据接口描述构造不同的参数输入值 输出:XML文件 二.实现方法 1.选用Python脚本来驱动测试 2.采用Excel表格管理测试数 ...

  7. python自动化测试框架结构_基于Python的HTTP接口自动化测试框架实现

    一.测试需求描述 对服务后台一系列的http接口功能测试. 输入:根据接口描述构造不同的参数输入值 输出:XML文件 二.实现方法 1.选用Python脚本来驱动测试 2.采用Excel表格管理测试数 ...

  8. http接口_基于Python的HTTP接口自动化测试框架实现

    一.测试需求描述 对服务后台一系列的http接口功能测试. 输入:根据接口描述构造不同的参数输入值 输出:XML文件 二.实现方法 1.选用Python脚本来驱动测试 2.采用Excel表格管理测试数 ...

  9. python接口测试_python接口自动化测试框架

    源码地址:tianfuzhiguo/shimo 由于github不支持大文件上传,打包好的客户端放在百度网盘上,客户端所需要的配置文件和用例模板在demo文件夹中 链接: https://pan.ba ...

最新文章

  1. CC 攻击检测研究现状
  2. Jackson相关的一些注解
  3. “AS3.0高级动画编程”学习:第二章转向行为(下)
  4. [react] react父子组件如何通信?
  5. Microsoft Visual Studio 打开代码出现乱码解决方案
  6. Gartner预测2017/18年十大物联网技术
  7. 关于软件定义IT基础设施的未来,深信服是这么思考的
  8. JQuery Highcharts 图表控件
  9. SpringMVC form:form的一个错误(没有传到前台绑定类)
  10. python是什么意思怎么读-python怎么读(python怎么读中文)
  11. 全面掌控你的苹果Mac:iStat Menus
  12. WIN10网络共享文件夹实战
  13. 菜鸟教程html5常用标签,HTML5 Canvas | w3cschool菜鸟教程
  14. Pytorch简单使用MINIST数据集
  15. 产品读书《周鸿祎-我的互联网方法论》
  16. 小米盒子显示未连接电脑连接服务器,小米盒子不能连接电脑的原因与解决办法...
  17. 看不见你的笑我怎么睡得着
  18. dCas9-ROS1——靶向去甲基化的捷径
  19. easyexcel 设置标题_Alibaba easyExcel对Excel操作之复杂标题处理
  20. 如何在web项目中访问HTML页面

热门文章

  1. 如何排查、解决那些长时间GC停顿的问题
  2. vscode之软著代码格式整理
  3. 百家姓128进制的权重和编码
  4. 无人货架的“新零售”逻辑:果、小、美
  5. blah什么意思_美剧中人们口中的“ damn ”到底是什么意思?
  6. 这份 Git 应急手册,关键时刻可保你一命
  7. 我和印度人一起值夜班
  8. 计算机相关的迎新标语,迎新横幅的标语(精选50句)
  9. java毕业设计“陶瓷的世界”网页的实际与实现Mybatis+系统+数据库+调试部署
  10. vertical-algin