当前位置: 首页 > news >正文

基于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、结果

图片

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

相关文章:

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

一、整体结构 框架组成:pytestrequestsallure 设计模式: 关键字驱动 项目结构: 工具层:api_keyword/ 参数层:params/ 用例层:case/ 数据驱动:data_driver/ 数据层:data/ 逻…...

【中间件】消息队列中间件intro

中间件middleware 内容管理 introwhy use MQMQ实现漫谈主流消息队列QMQ IntroQMQ架构QMQ 存储模型 本文还是从理论层面分析消息队列中间件 cfeng现在处于理论分析阶段,以中间件例子,之前的blog对于中间件是从使用角度分享了相关的用法,现在就…...

从 RBAC 到 NGAC ,企业如何实现自动化权限管理?

随着各领域加快向数字化、移动化、互联网化的发展,企业信息环境变得庞大复杂,身份和权限管理面临巨大的挑战。为了满足身份管理法规要求并管理风险,企业必须清点、分析和管理用户的访问权限。如今,越来越多的员工采用移动设备进行…...

vue3中如何使用TypeScript?

在Vue 3中引入和使用TypeScript非常简单。下面是在Vue 3中引入和使用TypeScript的步骤: 创建Vue 3项目:首先,使用Vue CLI创建一个新的Vue 3项目。可以使用以下命令: vue create my-project在创建项目时,选择TypeScri…...

Git基础操作:合并某个分支的一个目录到另一个分支

有的时候不小心在错误的分支A上开发了一点代码,也已经提交了;或者分支A原计划先上线的,但是业务调整需要插一个需求进来,但是插进来的需求中有一部分代码在分支A中已经写过了。 这个时候如果想把这部分代码移到正确的分支B上可以…...

学习grdecl文件格式

一、初步了解 最近在学习grdecl文件格式,文档不多。查找资料发现,这个格式的文件是由斯伦贝谢公司的ECLIPSE专业软件生成的。 搜到一些文档,都是2010年之前的,似乎有些用处。文档也交代了这个文件格式分为二进制和文本格式…...

Excel使用VLOOKUP查询数据

VLOOKUP函数在百度百科中的解释是: 解释一下,函数需要4个参数: 参数1(lookup_value):需要匹配的值参数2(table_array):在哪个区域里进行匹配参数3(col_index…...

SpectralGPT: Spectral Foundation Model 论文翻译2

遥感领域的通用大模型 2023.11.13在CVPR发表 原文地址:[2311.07113] SpectralGPT: Spectral Foundation Model (arxiv.org) 实验 ​ 在本节中,我们将严格评估我们的SpectralGPT模型的性能,并对其进行基准测试SOTA基础模型:ResN…...

Java编译过程中的JVM

流程 源代码编写: 首先,开发者使用Java编程语言编写源代码。这些源代码通常保存在扩展名为.java的文件中。 编译源代码: 使用Java编译器(例如javac),这些.java文件被编译成Java字节码。字节码是一种中间形…...

Python BDD 框架比较之 pytest-bdd vs behave

pytest-bdd和behave是 Python 的两个流行的 BDD 测试框架,两者都可以用来编写用户故事和可执行的测试用例, 具体选择哪一个则需要根据实际的项目状况来看。 先简单看一下两者的功能: pytest-bdd 基于pytest测试框架,可以与pytest…...

【面经八股】搜广推方向:常见面试题(一)

【面经&八股】搜广推方向:常见面试题(一) 文章目录 【面经&八股】搜广推方向:常见面试题(一)1. 线下效果提升、线上效果不好。2. XGBoost 和 GBDT是什么?有什么区别?3. 偏差与方差。延伸知识(集成学习的三种方式: Bagging、Boosting、Stacking)。4. 随机森林…...

斐讯K2结合Padavan实现锐捷认证破解方法

前言 众所周知,校园网在传统模式下是不能直接插路由使用的,但苦于校园网只能连接一台设备的烦恼,不得不“另辟蹊径”来寻求新的解决路径,这不,它来了,它来了,它带着希望走来了。 本文基于斐讯…...

SpringBoot : ch06 整合 web (一)

前言 SpringBoot作为一款优秀的框架,不仅提供了快速开发的能力,同时也提供了丰富的文档和示例,让开发者更加容易上手。在本博客中,我们将介绍如何使用SpringBoot来整合Web应用程序的相关技术,并通过实例代码来演示如何…...

C++:OJ练习(每日练习系列)

编程题: 题一:把字符串转换成整数 把字符串转换成整数_牛客题霸_牛客网 示例1 输入: "2147483647" 返回值: 2147483647思路一: 第一步:it从str的第一个字符开始遍历,定义一个最后输…...

C语言—什么是数组名

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int arr[]{1,2,3,4};printf("%p\n",arr);printf("%p\n",&arr);printf("%p\n",*arr);return 0; } 结论&#xff1a;数组名是数组首元素地址&#xff08;下标为0的元素…...

如何与死锁斗争!!!

其他系列文章导航 Java基础合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、死锁场景现场 二、死锁是如何产生的 三、死锁排查思路 四、sql模拟死锁复现 五、死锁的解决方案 前言 为避免影响业务&#xff0c;应尽可能避…...

【Java并发】聊聊不安全的HashMap以及ConcurrentHashMap

在实际的开发中&#xff0c;hashmap是比较常用的数据结构&#xff0c;如果所开发的系统并发量不高&#xff0c;那么没有问题&#xff0c;但是一旦系统的并发量增加一倍&#xff0c;那么就可能出现不可控的系统问题&#xff0c;所以在平时的开发中&#xff0c;我们除了需要考虑正…...

数据结构--->单链表

文章目录 链表链表的分类 单链表单链表的存储结构单链表主要实现的接口函数单链表尾插动态申请新节点单链表头插单链表的尾删单链表的头删在指定位置之前插入单链表查找插入 在指定位置之后插删除指定位置元素删除指定位置之后的元素顺序输出链表销毁单链表 顺序表和单链表的区…...

RT-Thread 线程间同步【信号量、互斥量、事件集】

线程间同步 一、信号量1. 创建信号量2. 获取信号量3. 释放信号量4. 删除信号量5. 代码示例 二、互斥量1. 创建互斥量2. 获取互斥量3. 释放互斥量4. 删除互斥量5. 代码示例 三、事件集1. 创建事件集2. 发送事件3. 接收事件4. 删除事件集5. 代码示例 简单来说&#xff0c;同步就是…...

B 树和 B+树 的区别

文章目录 B 树和 B树 的区别 B 树和 B树 的区别 了解二叉树、AVL 树、B 树的概念 B 树和 B树的应用场景 B 树是一种多路平衡查找树&#xff0c;为了更形象的理解。 二叉树&#xff0c;每个节点支持两个分支的树结构&#xff0c;相比于单向链表&#xff0c;多了一个分支。 …...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...