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

测开新手:pytest+requests+allure自动化测试接入Jenkins学习

最近在这整理知识,发现在pytest的知识文档缺少系统性,这里整理一下,方便后续回忆。

在python中,大家比较熟悉的两个框架是unittest和pytest:

Unittest是Python标准库中自带的单元测试框架,Unittest有时候也被称为PyUnit,就像JUnit是Java语言的标准单元测试框架一样,Unittest则是Python语言的标准单元测试框架。

Pytest是Python的另一个第三方单元测试库。它的目的是让单元测试变得更容易,并且也能扩展到支持应用层面复杂的功能测试。

两者之间的区别如下:

在这里插入图片描述

这里试用的pytest框架,加上request来实现接口自动化的测试,整个框架考虑到使用数据驱动的方式,将数据维护在Excel文档中。

1、下载安装allure

下载地址:

https://github.com/allure-framework/allure2/releases

https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/

选择需要的版本下载,这里我下载的是2.13.2版本

下载好后,解压到你需要存放的路目录,并配置环境变量

在这里插入图片描述

检查是否配置成功,执行cmd,输入命令 allure,出现如下图,则表示安装成功

图片

2、下载安装python

下载地址https://www.python.org/

下载好后,安装并配置环境变量,具体流程可以网络查找

3、python安装依赖包

cmd命令执行,也可以通过项目中的requirements.txt来安装,安装步骤后面再说

pip3 install allure-pytest
pip3 install pytest
pip3 install pytest_html
pip3 install request

4、下载并安装pycharm工具

查看网络教程

5、在pycharm,新建项目及编码

图片

项目目录如图:

base:存放一些最底层的方法封装,协议,请求发送等。

common:存放一些公共方法。

config:存放配置文件。

testData:存放测试数据。

log:存放日志。

report:存放报告。

testCase:存放用例。

utils:存放公共类。

readme:用于说明文档。

requirements.txt: 用于记录所有依赖包极其版本号,便于环境部署,可以通过pip命令自动生成和安装

图片

这里采用数据驱动的方式,数据通过读取excel文件来执行测试,所以这里需要封装读取excel的方法,使用xlrd来操作读取

# operationExcel.py
import jsonfrom common.contentsManage import filePath
import xlrd, xlwt
class OperationExcel:# 获取shell表def getSheet(self, index=0):book = xlrd.open_workbook(filePath())return book.sheet_by_index(index) #根据索引获取到sheet表# 以列表形式读取出所有数据def getExcelData(self, index=0):data = []sheet = self.getSheet(index=index)title = sheet.row_values(0) # (0)获取第一行也就是表头for row in range(1, sheet.nrows): # 从第二行开始获取row_value = sheet.row_values(row)data.append(dict(zip(title, row_value))) # 将读取出第一条用例作为一个字典存放近列表return data# 对excel表头进行全局变量定义
class ExcelVarles:case_Id = "用例ID"case_module="用例模块"case_name="用例名称"case_server="用例地址"case_url="请求地址"case_method="请求方法"case_type="请求类型"case_data="请求参数"case_headers="请求头"case_preposition="前置条件"case_isRun = "是否执行"case_code = "状态码"case_result = "期望结果"if __name__ == "__main__":opExcel = OperationExcel()# opExcel.getSheet()# print(opExcel.getExcelData())opExcel.writeExcelData(1, 7, f"test{2}")

excel 文件内容如图

图片

封装用例

# test_api_all.py
# 参数化运用所有用例
import json
import pytestfrom utils.operationExcel import OperationExcel, ExcelVarles
from base.method import ApiRequest
from common.log import loggeropExcel = OperationExcel()
apiRequest = ApiRequest()@pytest.mark.parametrize('data', opExcel.getExcelData()) # 装饰器进行封装用例
def test_api(data, login_token=None):if data[ExcelVarles.case_isRun] == "N" :logger.info("跳过执行用例")return# 请求头作为空处理并添加tokenheaders = data[ExcelVarles.case_headers]if len(str(headers).split()) == 0:passelif len(str(headers).split()) >= 0:headers = json.loads(headers) # 转换为字典#     headers['Authorization'] = login_token # 获取登录返回的token并添加到读取出来的headers里面headers = headers# 对请求参数做为空处理params = data[ExcelVarles.case_data]if len(str(params).split()) == 0:passelif len(str(params).split()) == 0:params = paramsurl = data[ExcelVarles.case_server] + data[ExcelVarles.case_url] + "?" + paramsr = apiRequest.all_method( data[ExcelVarles.case_method] ,url, headers=headers)logger.info(f"响应结果{r}")responseResult = json.loads(r)case_result_assert(data[ExcelVarles.case_code], responseResult['code'])# 断言封装
def case_result_assert(expectedResult, actualReuls) :'''断言封装:param expectedResult: 预期结果:param actualReuls: 实际结果:return:'''assert expectedResult == actualReuls # 状态码

封装日志文件

# log.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import logging
import time
import osfrom common.contentsManage import logDir# BASE_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
# # 定义日志文件路径
# LOG_PATH = os.path.join(BASE_PATH, "log")
# if not os.path.exists(LOG_PATH):
#     os.mkdir(LOG_PATH)# 方法1
# 封装自己的logging
class MyLogger:def __init__(self):self._logName = os.path.join(logDir(), "{}.log".format(time.strftime("%Y%m%d")))self._logger = logging.getLogger("logger")self._logger.setLevel(logging.DEBUG)self._formatter = logging.Formatter('[%(asctime)s][%(filename)s %(lineno)d][%(levelname)s]:%(message)s')self._streamHandler = logging.StreamHandler()self._fileHandler = logging.FileHandler(self._logName, mode='a', encoding="utf-8")self._streamHandler.setFormatter(self._formatter)self._fileHandler.setFormatter(self._formatter)self._logger.addHandler(self._streamHandler)self._logger.addHandler(self._fileHandler)# 获取logger日志记录器def get_logger(self):return self._loggerlogger = MyLogger().get_logger()

封装请求方法

# method.py
import json
import requests
from common.log import logger
from utils.commonUtils import isJsonclass ApiRequest(object):# ---- 第一种请求方式封装requests库,调用可根据实际情况传参 ----# def send_requests(self, method, url, data=None, params=None, headers=None,#                   cookies=None,json=None,files=None,auth=None,timeout=None,#                   proxies=None,verify=None,cert=None):#     self.res = requestes.request(method=method, url= url, headers=headers,data=data,#                                params=params, cookies=cookies,json = json,files=files,#                                auth=auth, timeout= timeout, proxies=proxies,verify=verify,#                                cert=cert)#     return self.res# 第二种封装方法def get(self, url, data=None, headers=None, payload=None):if headers is not None:res = requests.get(url=url, data=data,headers=headers)else:res = requests.get(url=url, data=data)return resdef post(self, url, data, headers, payload:dict, files=None):if headers is not None:res = requests.post(url=url, data=data, headers=headers)else :res = requests.post(url=url, data=data)if str(res) == "<Response [200]>" :return res.json()else :return res.textdef put(self,url,data,headers, payload:dict, files=None):if headers is not None :res = requests.put(url=url,data=data,headers=headers)else:res = requests.put(url=url,data=data)return resdef delete(self,url,data,headers, payload:dict):if headers is not None :res = requests.delete(url=url,data=data,headers=headers)else:res = requests.delete(url=url,data=data)return resdef all_method(self, method, url, data=None, headers=None, payload=None, files=None):logger.info(f"请求方法是{method}, 请求地址{url}")if headers == None:headers = {}if method.upper()=='GET':res = self.get(url,data,headers, payload)elif method.upper()=='POST':res = self.post(url, data, headers, payload, files)elif method.upper() == 'PUT':res = self.put(url, data, headers, payload, files)elif method.upper() == 'DELETE':res = self.delete(url, data, headers, payload)else :res = f'请求{method}方式不支持,或者不正确'return json.dumps(res, ensure_ascii=False, indent=4, sort_keys=True, separators=(',',':'))

运行

# run.py
import shutil
import pytest
import osfrom common.log import logger
import subprocess # 通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序
from common.contentsManage import htmlDir, resultDirif __name__ == '__main__':htmlPath = htmlDir()resultPath = resultDir()if os.path.exists(resultPath) and os.path.isdir(resultPath):logger.info("清理上一次执行的结果")shutil.rmtree(resultPath, True)logger.info("开始测试")pytest.main(["-s", "-v", "--alluredir", resultPath]) #运行输出并在resport/result目录下生成json文件logger.info("结束测试")# 如果是代码单独执行,需要立马看到报告,可以执行下面语句,如果配合Jenkins使用,则可以不需要执行,Jenkins自带的插件allure会操作# logger.info("生成报告")# subprocess.call('allure generate ' + resultPath + ' -o '+ htmlPath +' --clean', shell=True) # 读取json文件并生成html报告,--clean诺目录存在则先清楚# logger.info("查看报告")# subprocess.call('allure open -h 127.0.0.1 -p 9999 '+htmlPath+'', shell=True) #生成一个本地的服务并自动打开html报告

依赖包安装,可以执行命令 pip3 install -r requirements.txt,来安装

# requirements.txt
pytest==7.4.3
pytest-html==4.1.1
pytest-xdist==3.5.0
pytest-ordering==0.6
pytest-rerunfailures==13.0
allure-pytest==2.13.2
xlrd==1.2.0
requests==2.31.0

至此,项目的代码框架就基本结束了

6、安装并配置Jenkins

Jenkins的安装,看你需要在Windows还是Linux下安装,具体教程可以网络查找

Jenkins安装allure插件

图片

Jenkins安装并登录后,可以创建任务

图片

图片

图片

添加构建步骤,根据你安装环境的不同,选择不同的构建

图片

图片

添加构建后操作,选择 allure Report

图片

配置代码执行的结果地址

图片

运行测试后,可以在任务中查看allure生成的报告

图片

图片

至此,jenkins+python+pytest+requests+allure的接口自动化测试就记录到这里,刚兴趣的可以去看看pytest的官方文档,了解更多知识。

行动吧,在路上总比一直观望的要好,未来的你肯定会感谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入群: 1007119548,里面有各种测试开发资料和技术可以一起交流哦。

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取 【保证100%免费】

在这里插入图片描述

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。在这里插入图片描述
在这里插入图片描述在这里插入图片描述

相关文章:

测开新手:pytest+requests+allure自动化测试接入Jenkins学习

最近在这整理知识&#xff0c;发现在pytest的知识文档缺少系统性&#xff0c;这里整理一下&#xff0c;方便后续回忆。 在python中&#xff0c;大家比较熟悉的两个框架是unittest和pytest&#xff1a; Unittest是Python标准库中自带的单元测试框架&#xff0c;Unittest有时候…...

学习网络编程No.11【传输层协议之UDP】

引言&#xff1a; 北京时间&#xff1a;2023/11/20/9:17&#xff0c;昨天成功更文&#xff0c;上周实现了更文两篇&#xff0c;所以这周再接再厉。当然做题任在继续&#xff0c;而目前做题给我的感觉以套路和技巧偏多&#xff0c;还是那句话很多东西不经历你就是不懂&#xff…...

向爬虫而生---Redis 基石篇6 <拓展HyperLogLog>

前言: 继续之前的 向爬虫而生---Redis 基石篇5 &#xff1c;拓展Zset&#xff1e;-CSDN博客 一些比较基础的redis类型在初中级阶段用着没有毛病,但是到了大数据时代,慢慢一些更高级的场景,就需要把这几个类型搬出来了! 正文: 概念: 当我们需要对一个大型数据集进行去重计…...

JavaScript中的this

在实际应用中&#xff0c;了解 this 的行为是非常重要的&#xff0c;特别是在编写库或框架时&#xff0c;或者当你需要在回调函数中访问特定的上下文时&#xff0c;通常推荐使用箭头函数或者其他方法来确保 this 的正确指向。 在ES6中&#xff0c;this 的值取决于它是如何被调用…...

宝塔php站点设置伪静态规则 访问 a.com 时候跳转到 a.com/b.html

要在宝塔 PHP 站点中设置伪静态规则&#xff0c;实现访问a.com时跳转到a.com/b.html&#xff0c;可以按照以下步骤进行操作&#xff1a; 打开宝塔面板并登录到你的服务器管理界面。进入网站设置页面&#xff0c;找到你要设置伪静态规则的 PHP 站点。在站点设置中&#xff0c;找…...

git介绍4.2

git(版本控制工具) 一、git 介绍 1、git是目前世界上最先进的分布式版本控制系统&#xff0c;可以有效&#xff0c;高速的处理从小到大的项目版本管理。 2、git是linux torvalds 为了帮助管理linux内核开发二开发的一个开放源码的版本控制软件。 3、git作用&#xff1a;更好…...

【深入了解设计模式】组合设计模式

组合设计模式 组合模式是一种结构型设计模式&#xff0c;它允许你将对象组合成树状结构来表现“整体-部分”关系。组合模式使得客户端可以统一对待单个对象和组合对象&#xff0c;从而使得代码更加灵活和易于扩展。 概述 ​ 对于这个图片肯定会非常熟悉&#xff0c;上图我们可…...

4.Java---方法+重载

方法 方法的调用是需要开辟内存的,方法调用结束内存就被销毁了. 下面将介绍一个经典的错误标准的0分的示意! 我们日常中写交换两个数字的代码的时候都会用如下的方法进行描述: 你是不是觉得自己写的特别对!终于可以独立写一个小小的函数了? 下面运行一下看看结果 哦莫!怎么…...

蓝桥杯Java B组历年真题(2013年-2021年)

一、2013年真题 1、世纪末的星期 使用日期类判断就行&#xff0c;这里使用LocalDate&#xff0c;也可以使用Calendar类 答案 2099 使用LocalDate import java.time.LocalDate; import java.time.format.DateTimeFormatter; // 1:无需package // 2: 类名必须Main, 不可修改p…...

C++笔记(五)--- 虚函数(virtual)

目录 虚函数介绍 虚函数、覆盖和重载区别 虚函数介绍 C的虚函数是多态性的表现 1.构造函数不能为虚函数2.子类继承时虚函数仍为虚函数3.虚函数类外实现时&#xff0c;不需要加virtual4.有虚函数的类&#xff0c;析构函数一定要写成虚函数&#xff08;否则可能会造成内存泄漏&…...

编写加密程序,加密规则为:将所有字母转化为该字母后的第三个字母,即A->D、B->E

编写加密程序&#xff0c;加密规则为&#xff1a;将所有字母转化为该字母后的第三个字母&#xff0c;即A->D、B->E、C->F、…、Y->B、Z->C。小写字母同上&#xff0c;其他字符不做转化。输入任意字符串&#xff0c;输出加密后的结果。 例如&#xff1a;输入&qu…...

【笔记】:更方便的将一个List中的数据传入另一个List中,避免多重循环

这里是 simpleInfoList 集合&#xff0c;记为集合A&#xff08;传值对象&#xff09; List<CourseSimpleInfoDTO> simpleInfoList courseClient.getSimpleInfoList(courseIds);if(simpleInfoListnull){throw new BizIllegalException("当前课程不存在!");}这…...

Cisco Secure ACS 5.8.0.32 安装 + Crack 教程

Cisco Secure ACS 5.8.0.32 安装 Crack 教程 前言系统环境开始安装 开始破解导入授权文件 前言 在ESXi 6.7 上经历过无数次的安装尝试 测试了各种兼容版本都没有安装成功,记最后一次安装成功的过程. 系统环境 服务器 : Dell R720xd CPU : E5-2620 v2 系统 : ESXi 6.7…...

项目准备March

Nginx主要用来作为Http服务器&#xff0c;要实现Tomcat的负载均衡&#xff0c;就可以通过Nginx来实现。 正向代理代理的是客户端&#xff0c;反向代理代理的是服务端。SpringBoot采用约定优于配置的思想&#xff0c;简化Spring项目的配置开发。 前端请求其实并未直接发送到后…...

集智书童 | YOLO+混合注意力机制 | YOLOv5再加4.3%才可以做对手,Transformer混合设计依旧可以卷

本文来源公众号“集智书童”&#xff0c;侵权删&#xff0c;干货满满。YOLOv5重出江湖&#xff01; 原文链接&#xff1a;https://mp.weixin.qq.com/s/vb7HsA0fKDgRc3uC8Z-2yw 在工业生产过程中&#xff0c;由于低效率、不统一的评估、高成本以及缺乏实时数据&#xff0c;传统…...

Codeforces Round 894 (Div. 3)----->C. Flower City Fence

题目总思路&#xff1a; 要判断是否对称&#xff0c;只需要判断两个放法得到的图形是否相同&#xff08;竖着放&#xff0c;横着放&#xff09;&#xff0c;这两个放法有个很重要的特性&#xff1a;就是数组中大于1的个数&#xff0c;就是横着放时&#xff0c;第一竖排的高度。…...

CryoEM - CryoAI: Amortized Inference of Poses 工程源码复现

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/136384544 Paper: CryoAI: Amortized Inference of Poses for Ab Initio Reconstruction of 3D Molecular Volumes from Real Cryo-EM Images CryoAI: 基于摊…...

项目预备知识

导入两个头文件 #include <graphics.h> // 引入 EasyX 的图形库头文件 #include <conio.h> // 引入 conio.h 以使用 getch() 窗口创建函数&#xff1a;小黑屏 initgraph(640, 480, SHOWCONSOLE); closegraph(); //关闭一个窗口 设置背景颜色&#xff1a;这…...

redis实战笔记汇总

文章目录 1 NoSQL入门概述1.1 能干嘛&#xff1f;1.2 传统RDBMS VS NOSQL1.3 NoSQL数据库的四大分类1.4 分布式数据库CAP原理 BASE原则1.5 分布式集群简介1.6 淘宝商品信息的存储方案 2 Redis入门概述2.1 是什么&#xff1f;2.2 能干嘛&#xff1f;2.3 怎么玩&#xff1f;核心…...

elment-ui table表格排序后 清除排序箭头/恢复默认排序 的高亮样式

问题描述&#xff1a; 1.默认排序是按照名称升序排列&#xff08;图一&#xff09; 2.在选择了筛选项以及其他排序方式之后&#xff0c;箭头高亮是这样的&#xff08;图二&#xff09; 3.当我点击清空按钮后&#xff0c;类型清空了&#xff0c;并且传给后端的排序方式是名称/升…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

Axure 下拉框联动

实现选省、选完省之后选对应省份下的市区...