Pytest+Requests+Allure实现接口自动化测试

一、整体结构

  • 框架组成:pytest+requests+allure
  • 设计模式:
    • 关键字驱动
  • 项目结构:
    • 工具层:api_keyword/
    • 参数层:params/
    • 用例层:case/
    • 数据驱动:data_driver/
    • 数据层:data/
    • 逻辑层:logic/

二、具体步骤及代码

1、工具层
将get、post等常用行为进行二次封装。
代码(api_key.py)如下:

import allure
import json
import jsonpath
import requests# 定义一个关键字类
class ApiKey:# 将get请求行为进行封装@allure.step("发送get请求")def get(self, url, params=None, **kwargs):return requests.get(url=url, params=params, **kwargs)# 将post请求行为进行封装@allure.step("发送post请求")def post(self, url, data=None, **kwargs):return requests.post(url=url, data=data, **kwargs)# 由于接口之间可能相互关联,因此下一个接口需要上一个接口的某个返回值,此处采用jsonpath对上一个接口返回的值进行定位并取值@allure.step("获取返回结果字典值")def get_text(self, data, key):# json数据转换为字典json_data = json.loads(data)# jsonpath取值value = jsonpath.jsonpath(json_data, '$..{0}'.format(key))return value[0]
  • 其中引用allure.step()装饰器进行步骤详细描述,使测试报告更加详细。
  • 使用jsonpath对接口的返回值进行取值。

2、数据层
数据采用yaml文件。
代码(user.yaml)如下:

-user:username: adminpassword: '123456'msg: successtitle: 输入正确账号、密码,登录成功
-user:username: admin1password: '1234561'msg: 用户名或密码错误title: 输入错误账号1、密码1,登录失败
-user:username: admin2password: '1234562'msg: 用户名或密码错误title: 输入错误账号2、密码2,登录失败
  • 其中title是为了在用例进行时动态获取参数生成标题。

3、数据驱动层
对数据进行读写。
代码(yaml.driver.py)如下:

import yamldef load_yaml(path):file = open(path, 'r', encoding='utf-8')data = yaml.load(file, Loader=yaml.FullLoader)return data

4、参数层
参数层存放公共使用的参数,在使用时对其进行调用。
代码(allParams.py)如下:

'''规则:全局变量使用大写字母表示
'''# 地址
URL = 'http://39.98.138.157:'# 端口
PORT = '5000'

5、逻辑层

用例一:进行登录的接口请求,此处登录请求在yaml文件里设置了三组不同的数据进行请求。

用例二:进行个人查询的接口请求,此处需要用到登录接口返回的token值。

用例三、进行添加商品到购物车的接口请求,此处需要用到登录接口返回的token值以及个人查询接口返回的openid、userid值

用例四、进行下单的接口请求,此处需要用到登录接口返回的token值以及个人查询接口返回的openid、userid、cartid值

注意:由于多数接口需要用到登录接口返回的token值,因此封装一个conftest.py定义项目级前置fixture,在整个项目只执行一次,可以在各个用例中进行调用(其他共用参数也可以采取类似前置定义)。同时由于此处定义的项目级fixture,因此可以将初始化工具类ak = ApiKey()也放入其中。

代码(conftest.py)如下:

from random import randomimport allure
import pytestfrom pytest_demo_2.api_keyword.api_key import ApiKey
from pytest_demo_2.params.allParams import *def pytest_collection_modifyitems(items):"""测试用例收集完成时,将收集到的item的name和nodeid的中文显示在控制台上"""for item in items:item.name = item.name.encode("utf-8").decode("unicode_escape")item._nodeid = item.nodeid.encode("utf-8").decode("unicode_escape")# 项目级fix,整个项目只初始化一次
@pytest.fixture(scope='session')
def token_fix():# 初始化工具类ak = ApiKey()with allure.step("发送登录接口请求,并获取token,整个项目只生成一次"):# 请求接口# url = 'http://39.98.138.157:5000/api/login'url = URL + PORT + '/api/login'# 请求参数userInfo = {'username': 'admin','password': '123456'}# post请求res = ak.post(url=url, json=userInfo)# 获取tokentoken = ak.get_text(res.text, 'token')# 验证代码,验证token只生成一次token_random = random()return ak, token, res, token_random
  • 其中也包含了防止中文乱码,加入了pytest_collection_modifyitems(函数)。

设置好conftest后,就可以应用在逻辑层里面了。
代码(shopingApi.py)如下:

import pytest
import allure
from pytest_demo_2.api_keyword.api_key import ApiKey
from pytest_demo_2.params.allParams import *class ApiCase():# 登录逻辑def params_login(self, userdata):# 动态获取参数生成标题allure.dynamic.title(userdata['title'])# 初始化工具类ak = ApiKey()# 请求接口url = URL + PORT + '/api/login'# 请求参数userInfo = {'username': userdata['user']['username'],'password': userdata['user']['password']}res = ak.post(url=url, json=userInfo)with allure.step("接口返回信息校验及打印"):print("/api/login登录接口请求响应信息")print(res.text)# 获取响应结果msg = ak.get_text(res.text, 'msg')print(msg)# 断言assert msg == userdata['msg']def params_getuserinfo(self, token_fix):# 从fix中获取预置的工具类和token,所有返回值都需要接收ak, token, res, token_random01 = token_fixwith allure.step("发送个人查询接口请求"):url = URL + PORT + '/api/getuserinfo'headers = {'token': token}res1 = ak.get(url=url, headers=headers)with allure.step("接口返回信息校验及打印"):print("/api/getuserinfo个人用户查询接口请求响应信息")print(res1.text)# print("验证的random值,测试用")# print(token_random01)name = ak.get_text(res1.text, 'nikename')# 断言assert "风清扬" == namereturn res1def params_addcart(self, token_fix):# 从fix中获取预置的工具类和token# 所有返回都要获取,不然会报错ak, token, res, token_random01 = token_fixwith allure.step("调用getuserinfo接口获取返回信息"):res1 = self.params_getuserinfo(token_fix)with allure.step("发送添加商品到购物车请求"):# 添加商品到购物车,基于token、userid、openid、productidurl = URL + PORT + '/api/addcart'hd = {"token": token}data = {"userid": ak.get_text(res1.text, 'userid'),"openid": ak.get_text(res1.text, 'openid'),"productid": 8888}# 发送请求res2 = ak.post(url=url, headers=hd, json=data)with allure.step("接口返回信息校验及打印"):print("/api/addcart添加商品到购物车请求响应信息")print(res2.text)# print("验证的random值,测试用")# print(token_random01)result = ak.get_text(res2.text, 'result')assert 'success' == resultreturn res2def params_createorder(self, token_fix):ak, token, res, token_random01 = token_fixwith allure.step("调用addcart接口获取返回信息"):res1 = self.params_addcart(token_fix)with allure.step("发送下单请求"):url = URL + PORT + '/api/createorder'# 从项目级fix中获取tokenhd = {"token": token}# 从添加商品到购物车接口中获取userid,openid,cartiddata = {"userid": ak.get_text(res1.text, 'userid'),"openid": ak.get_text(res1.text, 'openid'),"productid": 8888,"cartid": ak.get_text(res1.text, 'cartid')}res2 = ak.post(url=url, headers=hd, json=data)with allure.step("接口返回信息校验及打印"):print("/api/createorder下单请求响应信息")print(res2.text)# print("验证的random值,测试用")# print(token_random01)result = ak.get_text(res1.text, 'result')assert 'success' == result

6、用例层
调用逻辑层进行用例管理和数据传输。
代码(test_Tree.py)如下:

import allure
import pytest
from pytest_demo_2.data_driver import yaml_driver
from pytest_demo_2.logic.shopingApi import ApiCase@allure.epic("shopXo电商平台接口-接口测试")
class TestTree():# 初始化用例库actions1 = ApiCase()@allure.feature("01.登陆")@allure.story("02.一般场景")@pytest.mark.parametrize('userdata', yaml_driver.load_yaml('./data/user.yaml'))def test_case01(self, userdata):self.actions1.params_login(userdata)@allure.feature("02.个人查询")@allure.story("01.典型场景")@allure.title("个人查询")def test_case02(self, token_fix):self.actions1.params_getuserinfo(token_fix)@allure.feature("03.添加商品到购物车")@allure.story("01.典型场景")@allure.title("添加商品到购物车")def test_case03(self, token_fix):self.actions1.params_addcart(token_fix)@allure.feature("04.下单")@allure.story("01.典型场景")@allure.title("下单")def test_case04(self, token_fix):self.actions1.params_createorder(token_fix)

7、运行
代码(main_run.py)如下:

import os
import pytestdef run():pytest.main(['-v', './case/test_Tree.py','--alluredir', './result', '--clean-alluredir'])os.system('allure serve result')# os.system('allure generate ./result/ -o ./report_allure/ --clean')if __name__ == '__main__':run()

8、结果

 

2023最新Jmeter接口测试从入门到精通(全套项目实战教程)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/295891.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

消息队列之关于如何实现延时队列

一、延时队列的应用 1.1 什么是延时队列? 顾名思义:首先它要具有队列的特性,再给它附加一个延迟消费队列消息的功能,也就是说可以指定队列中的消息在哪个时间点被消费。 延时队列在项目中的应用还是比较多的,尤其像…

手写题 - 实现一个带并发限制的异步调度器

题目 实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有N个。 完善下面代码中的 Scheduler 类,使得以下程序能正确输出:class Scheduler {add(promiseCreator) { ... }// ... }const timeout (time) > new Promise(re…

Quartz.NET 事件监听器

1、调度器监听器 调度器本身收到的一些事件通知,接口ISchedulerListener,如作业的添加、删除、停止、挂起等事件通知,调度器的启动、关闭、出错等事件通知,触发器的暂停、挂起等事件通知,接口部分定义如下&#xff1a…

[已解决]HttpMessageNotReadableException: JSON parse error: Unexpected character:解析JSON时出现异常的问题分析与解决方案

🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~&#x1f33…

C# SixLabors.ImageSharp.Drawing的多种用途

生成验证码 /// <summary> /// 生成二维码 /// </summary> /// <param name"webRootPath">wwwroot目录</param> /// <param name"verifyCode">验证码</param> /// <param name"width">图片宽度</…

Docker - 镜像 | 容器 日常开发常用指令 + 演示(一文通关)

目录 Docker 开发常用指令汇总 辅助命令 docker version docker info docker --help 镜像命令 查看镜像信息 下载镜像 搜索镜像 删除镜像 容器命令 查看运行中的容器 运行容器 停止、启动、重启、暂停、恢复容器 杀死容器 删除容器 查看容器日志 进入容器内部…

【数据结构入门精讲 | 第九篇】考研408排序算法专项练习(一)

前面几篇文章介绍的是排序算法&#xff0c;现在让我们开始排序算法的专项练习。 目录 判断题选择题填空题1.插入排序2.另类选择排序3.冒泡排序4.快速查找第K大元 判断题 1.希尔排序是稳定的算法。&#xff08;错&#xff09; 解析&#xff1a;稳定性是指如果两个元素在排序前后…

如何实现酷狗音乐pc页面点击播放时,打开多个歌曲播放时,始终在一个播放页面,(标签页的通讯)

大致有两种思路&#xff0c; 一种是通过wind.open()方法传第二个参数&#xff0c; A页面&#xff1a; //点击跳转播放页函数function toPlayPage(){window.open(path/xxxx/xxxx?name音乐名,music)//第二个参数写一个定值&#xff0c;代表跳转页面都为music标签页&#xff0…

vue.js组件的应用(Vite构建)

一.组件的定义和应用 1.全局组件 全局组件是指在任何页面中不必再单独引入组件并注册&#xff0c;直接在模板中使用组件名称就可以引用的组件。 全局组件注册方法一 先在src目录下新建一个globalComponents文件夹&#xff0c;再新建一个Header.vue的全局组件。 <templa…

Web前端 ---- 【Vue】vue路由守卫(全局前置路由守卫、全局后置路由守卫、局部路由path守卫、局部路由component守卫)

目录 前言 全局前置路由守卫 全局后置路由守卫 局部路由守卫之path守卫 局部路由守卫之component守卫 前言 本文介绍Vue2最后的知识点&#xff0c;关于vue的路由守卫。也就是鉴权&#xff0c;不是所有的组件任何人都可以访问到的&#xff0c;需要权限&#xff0c;而根据权限…

Java经典框架之Spring

Java经典框架之Spring Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring简介 2.…

RabbitMQ不公平分发与预取值

1.分发简介 RabbitMQ不设置的话默认采用轮询方式分发消息,你一个我一个(公平);但实际生活中,由于处理速度不同,若还采用轮询方式分发会导致处理速度快的空等待,因此我们采用不公平分发 2.不公平分发 在消费者这侧设置即可,以之前的Worker3和Worker4为例 2.1.Worker3 packa…