如何通过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 json

from 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 pytest

from utils.operationExcel import OperationExcel,ExcelVarles

from base.method import ApiRequest

from common.log import logger

opExcel=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

#请求头作为空处理并添加token

headers=data[ExcelVarles.case_headers]

if len(str(headers).split())==0:

pass

elif 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:

pass

elif len(str(params).split())==0:

params=params

url=data[ExcelVarles.case_server]+data[ExcelVarles.case_url]+"?"+params

r=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 os

from 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._logger

logger=MyLogger().get_logger()

封装请求方法

#method.py

import json

import requests

from common.log import logger

from utils.commonUtils import isJson

class 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 res

def 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.text

def 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 res

def 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 res

def 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 os

from common.log import logger

import subprocess#通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序

from common.contentsManage import htmlDir,resultDir

if__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的官方文档,了解更多知识。

文末了:

可以到我的个人号:atstudy-js,可以免费领取一份10G软件测试工程师面试宝典文档资料。同时我邀请你进入我们的软件测试学习交流平台,大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,了解测试行业的最新趋势,助你快速进阶Python自动化测试/测试开发,稳住当前职位同时走向高薪之路。

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

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

相关文章

2024腾讯云服务器购买指南一步步全流程攻略(超详细)

腾讯云服务器购买流程很简单&#xff0c;有两种购买方式&#xff0c;直接在官方活动上购买比较划算&#xff0c;在云服务器CVM或轻量应用服务器页面自定义购买价格比较贵&#xff0c;但是自定义购买云服务器CPU内存带宽配置选择范围广&#xff0c;活动上购买只能选择固定的活动…

基于SPI的插件式开发实现方案之@AutoService+ServiceLoader介绍及Dolphinscheduler中的实际应用

1.插件化开发概述 插件化开发模式正在很多编程语言或技术框架中得以广泛的应用实践&#xff0c;比如大家熟悉的jenkins&#xff0c;docker可视化管理平台rancher&#xff0c;以及日常编码使用的编辑器idea&#xff0c;vscode等。 实现服务模块之间解耦的方式有很多&#xff0…

22.实战演练--记住密码和登录状态

在登录注册案例的基础上&#xff0c;实现一个相对完整的登录注册模块 (1).记住密码 (2).记住登录状态&#xff08;自动登录&#xff09; (3).注册成功&#xff0c;登录成功&#xff0c;退出登录时的页面跳转

雍禾医疗好医生:雍禾植发张华医生立志服务好毛发患者

作为中国领先的专门从事毛发医疗服务的医疗集团&#xff0c;雍禾医疗提供诊疗、植发、养固等一站式毛发医疗服务&#xff0c;旗下拥有由专业植发品牌“雍禾植发”、医疗养固品牌“史云逊”、女性美学植发品牌“雍禾发之初”及医学假发品牌“哈发达”等组成的全产业链品牌矩阵。…

MySQL 协议(非常详细适合小白学习)

MySQL 查询过程 MySQL 查询过程大致如下&#xff1a; 1&#xff09;客户端与服务器端建立连接&#xff1b; 2&#xff09;客户端登陆 MySQL&#xff1b; 3&#xff09;客户端向服务器端发起一条请求&#xff1b; 4&#xff09;服务器端先检查查询缓存&#xff0c;如果命中缓…

哈希(hash)

目录 一、什么是哈希 二、哈希冲突 三、哈希函数 3.1、哈希函数设计原则 3.2、常见的哈希函数 四、哈希冲突解决 4.1、闭散列 4.2、开散列 五、哈希表的模拟实现 5.1、哈希表的功能模拟实现 5.2、测试模拟实现&#xff1a; 一、什么是哈希 如果构造一种存储结构&…

实例分割模型Mask2Former解析

Masked2Former是在mask rcnn基础上改进的一个实例分割模型&#xff0c;参考了一些经典模型的思想&#xff0c;如DETR&#xff0c;实验表明效果很好。 论文&#xff1a;《Masked-attention Mask Transformer for Universal Image Segmentation》 https://arxiv.org/abs/2112.0…

新手必看:腾讯云服务器购买详细图文教程

腾讯云服务器购买流程很简单&#xff0c;有两种购买方式&#xff0c;直接在官方活动上购买比较划算&#xff0c;在云服务器CVM或轻量应用服务器页面自定义购买价格比较贵&#xff0c;但是自定义购买云服务器CPU内存带宽配置选择范围广&#xff0c;活动上购买只能选择固定的活动…

【极光系列】Windows安装Mysql8.0版本

【极光系列】Windows安装Mysql8.0版本 一.mysql服务端 下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 二.解压二进制包 解压到 E:\mysql-8.0.35-winx64目录下&#xff0c;记住你解压后的目录&#xff0c;后续要使用三.创建my.ini文件 tips&#xff1a;mys…

nvcc -V显示command not found

出现这个问题&#xff0c;不仅是 nvcc -V会显示command not found,nvidia-smi同样也会显示 解决方法如下&#xff1a; 1&#xff09;这里首先转换到CUDA所在位置&#xff0c;一般是在这个位置 cd /usr/local 2&#xff09;打开、编辑环境变量的配置文件 vim ~/.bashrc …

使用HTTP/2在Linux上的Nginx服务器进行优化

随着互联网的发展&#xff0c;HTTP/2协议逐渐成为主流。与传统的HTTP/1.1相比&#xff0c;HTTP/2提供了更高的传输效率和更好的安全性。在Linux上使用Nginx服务器进行优化&#xff0c;我们可以充分利用HTTP/2的优势&#xff0c;提高网站的性能和用户体验。 1. 安装Nginx并启用…

日志采集传输框架之 Flume,将监听端口数据发送至Kafka

1、简介 Flume 是 Cloudera 提供的一个高可用的&#xff0c;高可靠的&#xff0c;分布式的海量日志采集、聚合和传 输的系统。Flume 基于流式架构&#xff0c;主要有以下几个部分组成。 主要组件介绍&#xff1a; 1&#xff09;、Flume Agent 是一个 JVM 进程&#xf…

【JupyterLab】在 conda 虚拟环境中 JupyterLab 的安装与使用

【JupyterLab】在 conda 虚拟环境中 JupyterLab 的安装与使用 1 JupyterLab 介绍2 安装2.1 Jupyter Kernel 与 conda 虚拟环境 3 使用3.1 安装中文语言包(Optional)3.2 启动3.3 常用快捷键3.3.1 命令模式下 3.4 远程访问个人计算机3.4.1 局域网下 1 JupyterLab 介绍 官方文档: …

15.鸿蒙HarmonyOS App(JAVA)进度条与圆形进度条

15.鸿蒙HarmonyOS App(JAVA)进度条与圆形进度条 progressBar2.setIndeterminate(true);//设置无限模式,运行查看动态效果 //创建并设置无限模式元素 ShapeElement element new ShapeElement(); element.setBounds(0,0,50,50); element.setRgbColor(new RgbColor(255,0,0)); …

Nginx——强化基础配置

1、牢记Context Context是Nginx中每条指令都会附带的信息&#xff0c;用来说明指令在哪个指令块中使用&#xff0c;可以将Context 理解为配置环境。 每个指令都拥有自己的配置环境&#xff0c;如果把配置环境记错了&#xff0c;或者在设计时未考虑配置环境的作用&#xff0c;…

【闯关练习】—— 1400分(构造)

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;cf闯关练习 &#x1f48c;其他专栏&#xff1a; &#x1f534;每日一题 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓…

STM32F103标准外设库——寄存器 (二)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;V…

LeetCode刷题---逆波兰表达式求值

解题思路&#xff1a; 使用栈来解决该问题 首先定义一个栈Stack&#xff0c;接着对tokens数组进行遍历&#xff0c;如果当前元素是非数字字符串的话(运算符)&#xff0c;就从栈中取出两个元素根据该运算符进行计算&#xff0c;将计算后的结果添加到栈中。如果当前元素是数字字符…

基于Spring Boot+vue的云上新鲜水果超市商城系统

本云上水果超市是为了提高用户查阅信息的效率和管理人员管理信息的工作效率&#xff0c;可以快速存储大量数据&#xff0c;还有信息检索功能&#xff0c;这大大的满足了用户、员工信息和管理员这三者的需求。操作简单易懂&#xff0c;合理分析各个模块的功能&#xff0c;尽可能…

【翻译】Qt Designer 如何使用资源文件

原文地址&#xff1a;https://doc.qt.io/qt-6/designer-resources.html Qt的资源浏览器是用于管理应用程序资源的工具&#xff0c;可以让开发者方便地查看和管理应用程序中的各种资源文件&#xff0c;例如图像、字体、布局文件、对话框等。 资源浏览器提供了一个可视化的界面&…