pytest+requests+allure自动化测试接入Jenkins学习

news2024/11/19 0:39:18

🍅 视频学习:文末有免费的配套视频可观看

🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快

最近在这整理知识,发现在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的官方文档,了解更多知识。

同时,在这我为大家准备了一份软件测试视频教程(含面试、接口、自动化、性能测试等),就在下方,需要的可以直接去观看。

字节大佬,一周讲完,自动化测试项目实战,这套教程是怎么称霸B站的?【2024最新版】

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

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

相关文章

MCU为什么上电不启动

相信很多朋友们都遇到过&#xff0c;自信满满的将程序下载到板子上&#xff0c;发现MCU居然没启动。 那这个现象可能有很多问题会导致&#xff0c;让我们来看看会有哪些原因。 1、BOOT引脚电平不对&#xff1a; 在GD32 MCU上&#xff0c;BOOT引脚决定了MCU的启动方式&#x…

zabbix监控深信服AD案例+自动发现虚拟服务和链路

文章目录 前言监控功能告警功能 环境准备操作步骤深信服AD开启SNMPSNMP V2SNMP V3 Zabbix导入模版Zabbix中添加深信服AD 前言 深信服AD&#xff0c;应用交付网关&#xff0c;是较为常见的应用发布、负载均衡设备&#xff0c;常用于网络出口。 本案例是通过zabbix的snmp监控深…

拥抱AI-图片学习中的卷积神经算法详解

一、定义 卷积神经算法&#xff08;Convolutional Neural Networks, CNN&#xff09;是深度学习领域中的一种重要算法&#xff0c;特别适用于处理图像相关的任务。以下是卷积神经算法的详细解释&#xff1a; 1. 基本概念 定义&#xff1a;卷积神经网络是一类包含卷积计算且具…

网络代理加速器:太阳HTTP的新一代解决方案(网络代理IP)

在当今数字化时代&#xff0c;网络速度与稳定性是企业和个人用户最为关注的重要问题之一。面对不稳定的网络连接&#xff0c;延迟高和速度慢等问题&#xff0c;传统的网络代理已经难以满足用户的需求。 为了解决这一问题&#xff0c;太阳HTTP推出了全新一代的网络代理加速器&a…

SQL Server 2016导入.bak文件到数据库里面步骤

1、打开SSMS管理器 选择数据库 右键 然后点击还原数据库。 2、选择设备 然后点击三个点 找到本地bak文件&#xff0c;然后点击确定 3、点击确定&#xff0c;会自动弹出来一个成功的提示。

消费增值模式引领业绩飙升与用户活跃

大家好&#xff0c;我是吴军&#xff0c;致力于为您揭示私域电商领域的独特魅力与机遇。 今日&#xff0c;我很高兴与大家分享一个激动人心的成功案例。我们的客户在短短一个月的时间里&#xff0c;业绩就飙升至上百万级别&#xff0c;其用户活跃度更是居高不下&#xff0c;日…

express+宝塔实现文件上传服务

文章目录 服务器部分开启存放文件的端口配置nginx该端口入口手动在/www/wwwroot/file目录下存放一张图片进行访问 express接口部分代码测试 服务器部分 开启存放文件的端口 我这里以83为例 先到对应的服务商开启端口&#xff0c;比如我这里是阿里云 测试&#xff0c;比如这里…

武汉凯迪正大—绝缘强度的测试设备 工频高压耐压交流试验仪 工频耐压试验机

武汉凯迪正大电气有限公司生产KDJS-8A全自动工频耐压试验系统&#xff08;10kVA全自动操作台&#xff09;&#xff0c;是根据国家行业试验标准而设计的试验设备&#xff0c;其安全可靠、功能强、使用方便、维护简单。主要用于对各种电器产品、电气元件、绝缘材料等进行规定电压…

vue3根据按钮切换更新echarts对应的数据

效果图 初始化注意 setOption的函数定义&#xff0c;option是指图表的配置项和数据&#xff0c;notMerge是指是否不跟之前设置的 option 进行合并。默认为 false。即表示合并。如果为 true&#xff0c;表示所有组件都会被删除&#xff0c;然后根据新option 创建所有新组件 //…

如何学习Django4?看这16堂课就够了

目录 写在前面 推荐图书 内容简介 作者简介 前言/序言 改编说明 推荐理由 写在后面 写在前面 本期博主给大家推荐一本关于Python Django4的图书&#xff08;2024年3月刚出版&#xff09;&#xff0c;感兴趣的小伙伴快来看看吧&#xff01; 推荐图书 《Python Django…

网络安全比赛-网络安全事件响应-Server2216(解析)

B-5:网络安全事件响应 任务环境说明: 服务器场景:Server2216(开放链接) 用户名:root密码:123456 1、黑客通过网络攻入本地服务器,通过特殊手段在系统中建立了多个异常进程,找出启动异常进程的脚本,并将其绝对路径作为Flag值提交; 2、黑客通过网络攻入本地服务器,…

72、AndroidStudio 导入项目Connect timed out错误解决

一、背景&#xff1a; 开发过程中难免会 clone 其他的项目&#xff0c;clone 或者下载成功之后。使用 android studio 打开项目时经常遇到 Connect timed out错误如图所示&#xff1a; 二、分析原因&#xff1a; 1、既然链接超时&#xff0c;肯定是 android studio 在运行…

python 魔术方法备忘录

python 魔术方法备忘录 网上收集了一些&#xff0c;列出了比较常用的&#xff0c;特别是第一张。 Python中的魔术方法&#xff08;Magic Methods&#xff09;&#xff0c;也被称为特殊方法&#xff08;Special Methods&#xff09;或双下划线方法&#xff08;Dunder Methods&a…

开放式耳机哪个品牌质量比较好?2024热门王炸品牌推荐!

开放式耳机市场繁杂&#xff0c;品质参差不齐。网红推荐、广告轰炸&#xff0c;让人眼花缭乱。但音频工程师告诉你&#xff0c;音质和舒适度才是关键。我根据多款开放式耳机测评结果&#xff0c;为大家提供选购指南&#xff0c;助你避开陷阱&#xff0c;找到心仪之选。 1、购买…

老版_zabbix安装与grafana可视化的安装(zabbix插件4.1.4)

grafana()的安装 查询、可视化和理解数据&#xff0c;并获取数据警报&#xff0c;无论数据存储在何处。在 Grafana&#xff0c;您可以通过美观、灵活的数据面板创建、探索和共享所有数据。 1. 网络下载安装 [itwisenode2 ]$ cd /opt/software/ #进入下载目录 #下载wegt安装命…

设计模式学习(二)工厂模式——工厂方法模式

设计模式学习&#xff08;二&#xff09;工厂模式——工厂方法模式 前言工厂方法模式简介示例优点缺点使用场景 前言 前一篇文章介绍了简单工厂模式&#xff0c;提到了简单工厂模式的缺点&#xff08;违反开闭原则&#xff0c;扩展困难&#xff09;&#xff0c;本文要介绍的工…

地面沉降数值模拟实践技术应用与案例分析教程

原文链接&#xff1a;地面沉降数值模拟实践技术应用与案例分析教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247606571&idx4&sn426fd43d2f9a21e3b550c6b5da0be860&chksmfa8260cccdf5e9da7af49e796287d3756cc7052f3be17b01a0adac9c2caf2e1e6680bde…

爱普生SMD3225贴片晶振升级版TSX-3225

爱普生有一款外形尺寸3.2*2.5mm的无源贴片晶振&#xff0c;型号TSX-3225&#xff0c;也是非常直观的能从型号分辨其封装尺寸大小的&#xff0c;被广泛应用于便携式的无线传输设备&#xff0c;同时&#xff0c;这也是一款非常成熟的产品&#xff0c;毕竟SMD3225封装是目前市场主…

量产导入 | KGD 是什么?

文章目录 KGD 是什么&#xff1f;认识KGD定义、功能与应用实例【白话文解析】Known Good「Die」何谓良品裸晶粒 &#xff08;KGD/KGD Die&#xff09;&#xff1f;解读KGD产业应用为什么大家纷纷采用KGD&#xff1f; 一窥KGD与芯片封测大趋势 KGD 是什么&#xff1f;认识KGD定义…

AMEYA360代理品牌:ROHM开发出世界超小CMOS运算放大器,适用于智能手机和小型物联网设备等应用

全球知名半导体制造商ROHM(总部位于日本京都市)开发出一款超小型封装的CMOS运算放大器“TLR377GYZ”&#xff0c;该产品非常适合在智能手机和小型物联网设备等应用中放大温度、压力、流量等的传感器检测信号。 智能手机和物联网终端越来越小型化&#xff0c;这就要求搭载的元器…