使用python+pytest+requests完成自动化接口测试(包括html报告的生成和日志记录以及层级的封装(包括调用Json文件))

news2025/1/18 14:07:45

一、API的选择

我们进行接口测试需要API文档和系统,我们选择JSONPlaceholder免费API,因为它是一个非常适合进行接口测试、API 测试和学习的工具。它免费、易于使用、无需认证,能够快速帮助开发者模拟常见的接口操作(增、删、改、查)。尤其对于我你们学习接口测试的初学开发者来说,它是一个理想的选择。

注意:这个API网站当我们发送请求时他不会真的实现我们的请求,他只会会虚拟实现我们的请求,并不会真的修改服务器数据。

二、环境的准备

在开始编写测试代码之前,我们需要先配置好环境。这包括安装所需的Python库并准备好相应的配置文件。

安装Python依赖

首先,确保你已经安装了Python。然后使用pip来安装所需的库。

pip install requests pytest

三、利用requests发送增删改查请求并用pytest测试用例管理框架管理测试用例

在接口自动化测试中,我们需要通过HTTP协议与服务器进行交互。requests库提供了多种方法来发送HTTP请求,常用的有GETPOSTPUTDELETE等。接下来,我们将分别讲解如何使用requests发送这些请求。

数据准备:

首先我们先确定我们的文件层级关系

project/
│
├── init.py         #里面存放一些初始化数据如URL   
├── test_practice.py   测试用例主要代码书写位置
test_log.log        # 日志文件(这里我使用vscode写代码所以我把日志文件放在了和项目目录同级,
#pyCharm可能需要和test_practice.py同级放置)
├── data_test.json  #存放参数化测试数据

init.py文件中我们放入url和单次运行测试用例所需的如下数据:

url="http://jsonplaceholder.typicode.com/posts/"

#data_updata为修改请求时用的数据
data_updata={
    "id":1,
    "title": 'updata',
    "body": 'bar',
    "userId": 1
  }

#data_add为增加请求时用的数据
data_add={
    "id":1,
    "title": 'updata',
    "body": 'bar',
    "userId": 1
  }

data_test.json文件中我们放入参数化执行测试用例时所需的数据 ,参数化时我们批量加入三组数据,201为响应状态码用于后期断言(就是判断是否请求成功)时用,如过返回的状态码是201则为成功,不同的请求拥有不同的响应状态码,都是由API文档规定的。

{"data":[
    [{"title": "updata1","body": "bar","userId": 1},201],
    [{"title": "updata2","body": "bar","userId": 2},201],
    [{"title": "updata3","body": "bar","userId": 3},201]
    ]
}

1、get查询

用requests进行接口测试其实很简单,就是头文件包含requests然后,调用它的不同方法,输入不同参数,它就会返回一个结果他就是响应报文,我们定义一个变量接收受它,然后用报文的不同数据进行断言或查看来判断接口是否正常。

# 查询全部数据
def test_get_all_information():
    #init是文件名,init.url表示该文件下的url变量
    res=requests.get(init.url)
    #输入他的响应体报文
    print(res.json())
    assert res.status_code==200


# 查询指定数据
def test_get_information():
    #url的书写方法可以用基本的字符串拼接
    res=requests.get(init.url+"/100")
    print(res.json())
    assert res.status_code==200

2、post新增

这一块包括发送一个post请求和批量发送post请求,post请求时我们需要传入我们要添加的数据这和利用postman进行接口测试是一样的,这里是以函数参数的方式发送数据的。

批量发送post请求时我们需要@pytest.mark.parametrize()来修饰测试方法。@pytest.mark.parametrize()它的参数由两部分构成,一是你需要传给下面测试方法的参数我们用"参数,参数"这种形式来书写,另一部分是我们要传入的测试数据,测试数据里的数据和第一部分里定义的参数一一对应,例如我的第一部分定义的参数有两个一个是新增请求的数据,一个是响应状态码,我的数据就是 [{"title": "updata1","body": "bar","userId": 1},201],中括号里的是新增请求的数据,201是状态码。然后其他的就和单个进行post请求一模一样了,不同的是断言时我们不用在直接写201,而是用code参数代替。这其实也是一个封装。

# 添加数据
def test_post_information():
    res=requests.post(init.url,data=data_add)
    print(res.json())
    assert res.status_code==201


# 参数化批量添加数据
@pytest.mark.parametrize("Placeholder_data,code",test_data)
def test_many_post_information(Placeholder_data,code):
    res=requests.post(init.url,data=Placeholder_data)
    print(res.json())
    assert res.status_code==code
    #assert res.json()==Placeholder_data

你运行完数据后会发现返回的数据 res.json()和我们传入的数据不一致,这是因为服务器对我们的数据做了自适应修改,我们传入的数据可能不利于它存储所以他会做改变,不同服务器有不同特性,JSONPlaceholder服务器就会在我们发送put修改请求时给我们返回的数据加一个字段id。

3、put修改

put修改和post基本一致,也需要我们发送修改新数据,不同的一点是你需要指定你要修改的数据是那个,你可以在url上+"/1"来指定你所要修改的是id为1的参数。

# 修改数据
def test_put_information():
  res=requests.put(init.url+"/1",data=test_data)
  
  print(res.status_code)
  assert res.status_code==200
  print(res.json())
  #print(type(res.json()["id"]))
  #print(type(test_data[0][0]["userId"]))
  # assert res.json()==test_data

4、delete删除,

delete请求方法不需要我们传入数据。如何响应状态码为200,说明我们删除成功。

# 删除数据
def test_delete_information():
    res=requests.delete(init.url+"/99")
    assert res.status_code==200

四、日志的生成

在生成日志时我们需要包含logging库,然后定义一个setup_logging函数在初始化日志的等级,日志的生成格式,以及日志问价的文件名位置,打开方式,以及编码方式。然后调用该函数在执行测试用例之前。我们还需要在不同的请求方法中通过使用logging.info来写入日志数据,例如我们在assert res.status_code==200后面加上logging.info("GET 请求成功"),就表示当断言成功完成时我们在日志种写入"GET 请求成功"的数据。如果你想你的日志详细些,就多加入一些数据输出,但是一般我们日志需要写的详细一点,每一步都写日志有助于后期我们排查问题。

import pytest
import requests
import json
import init
import logging

# 配置日志
def setup_logging():
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler("test_log.log",mode='a',encoding="utf-8"),
            # logging.StreamHandler()
        ]
    )

setup_logging()


data=json.load(open("./data_test.json",mode="r",encoding="utf-8"))

# 数据准备
# print(type(data))
test_data=data["data"]
# print(test_data)
data_updata=init.data_updata
data_add=init.data_add


# 查询全部数据
def test_get_all_information():
    logging.info(f"发送 GET 请求到 {init.url}")
    res=requests.get(init.url)
    # 记录请求和响应的内容
    logging.info(f"请求URL: {res.request.url}")
    logging.info(f"响应状态码: {res.status_code}")
    logging.info(f"响应数据: {res.text[:200]}")  # 仅输出前200个字符
    print(res.json())
    assert res.status_code==200
    logging.info("GET 请求成功")

# 参数化批量添加数据
@pytest.mark.parametrize("Placeholder_data,code",test_data)
def test_many_post_information(Placeholder_data,code):
    logging.info(f"发送 POST 请求到 {init.url},数据:{Placeholder_data}")
    res=requests.post(init.url,data=Placeholder_data)
    logging.info(f"请求URL: {res.request.url}")
    logging.info(f"请求数据: {Placeholder_data}")
    logging.info(f"响应状态码: {res.status_code}")
    logging.info(f"响应数据: {res.json()}")
    print(res.json())
    assert res.status_code==code
    logging.info("POST 请求成功")

# 添加数据
def test_post_information():
    logging.info(f"发送 POST 请求到 {init.url},数据:{data_add}")
    res=requests.post(init.url,data=data_add)
    logging.info(f"请求URL: {res.request.url}")
    logging.info(f"请求数据: {data}")
    logging.info(f"响应状态码: {res.status_code}")
    logging.info(f"响应数据: {res.json()}")
    print(res.json())
    assert res.status_code==201
    logging.info("POST 请求成功")

# 修改数据
def test_put_information():
    logging.info(f"发送 PUT 请求到 {init.url},数据:{test_data}")
    res=requests.put(init.url+"/1",data=test_data)
    logging.info(f"请求URL: {res.request.url}")
    logging.info(f"请求数据: {test_data}")
    logging.info(f"响应状态码: {res.status_code}")
    logging.info(f"响应数据: {res.json()}")
    print(res.status_code)
    assert res.status_code==200
    logging.info("PUT 请求成功")
    # print(res.json())
    # print(type(res.json()["id"]))
    print(type(test_data[0][0]["userId"]))
    # assert res.json()==test_data

# 查询指定数据
def test_get_information():
    logging.info(f"发送 GET 请求到 {init.url}")
    res=requests.get(init.url+"/100")
    logging.info(f"请求URL: {res.request.url}")
    logging.info(f"响应状态码: {res.status_code}")
    logging.info(f"响应数据: {res.json()}")
    print(res.json())
    assert res.status_code==200
    logging.info("GET 请求成功")

# 删除数据
def test_delete_information():
    logging.info(f"发送 DELETE 请求到 {init.url}")
    res=requests.delete(init.url+"/99")
    logging.info(f"请求URL: {res.request.url}")
    logging.info(f"响应状态码: {res.status_code}")
    logging.info(f"响应数据: {res.json()}")
    assert res.status_code==200
    logging.info("DELETE 请求成功")


if __name__ == "__main__":
    test_get_all_information()
    # test_many_post_information(Placeholder_data,code)
    test_post_information()
    test_put_information()
    test_get_information()
    test_delete_information()

logging.shutdown()

很奇怪的是当我用pytest命令行来运行测试用例时,我的测试用例成功执行完毕,但是 我的logging.log日志文件中并没有日志生成,会报UnicodeDecodeError: 'gbk' codec can't decode byte 0xaf in position 44: illegal multibyte sequence的错,我尝试了很多方法都失败了,但是当我用if __name__ == "__main__":运行日志时,就可以成功生成日志文件,如下图,不知是什么原因有知道的小伙伴可以评论区告诉我,非常感谢

五、生成html格式的测试报告

安装 pytest-html 插件

首先,确保你安装了 pytest-html 插件。如果没有安装,可以使用以下命令进行安装:

pip install pytest-html

使用 pytest-html 生成 HTML 测试报告

在运行测试时,可以通过 --html 选项来生成 HTML 格式的测试报告。例如,以下命令会生成一个名为 report.html 的 HTML 报告:

pytest --html=report.html --self-contained-html
  • --html=report.html:指定生成报告的文件名和路径。
  • --self-contained-html:生成一个独立的 HTML 文件,所有的 CSS 和 JavaScript 都会嵌入到 HTML 文件中。

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

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

相关文章

UE4原生的增量Cook原理

设置Cook的步骤后&#xff0c;断点进入到如下堆栈&#xff1a; UCookOnTheFlyServer::StartCookByTheBook(const UCookOnTheFlyServer::FCookByTheBookStartupOptions &) CookOnTheFlyServer.cpp:7723 UCookCommandlet::CookByTheBook(const TArray<…> &, TArr…

C#表达式和运算符

本文我们将学习C#的两个重要知识点&#xff1a;表达式和运算符。本章内容会理论性稍微强些&#xff0c;我们会尽量多举例进行说明。建议大家边阅读边思考&#xff0c;如果还能边实践就更好了。 1. 表达式 说到表达式&#xff0c;大家可能感觉有些陌生&#xff0c;我们先来举个…

蓝桥杯 Python 组知识点容斥原理

容斥原理 这张图初中或者高中数学课应该画过 也就是通过这个简单的例子引出容斥原理的公式 这张图的面积&#xff1a;s1 s3 s7 - 2 * s2 - 2 * s4 - 2 * s6 3 * s5 通过此引导出容斥原理公式 那么下面来一起看看题目 题目描述 给定 n,m 请求出所有 n 位十进制整数中有多…

PDF文件提取开源工具调研总结

概述 PDF是一种日常工作中广泛使用的跨平台文档格式&#xff0c;常常包含丰富的内容&#xff1a;包括文本、图表、表格、公式、图像。在现代信息处理工作流中发挥了重要的作用&#xff0c;尤其是RAG项目中&#xff0c;通过将非结构化数据转化为结构化和可访问的信息&#xff0…

PDF编辑 PDF-XChange Editor Plus 免装优化版

PDF编辑器很多打工人都需要用到&#xff0c;也分享过好几款口碑不错的&#xff0c;这次这款PDF依旧值得你的期待。 PDF-XChange Editor&#xff0c;号称打开速度最快最强大的PDF编辑器/PDF阅读器&#xff0c;专注于PDF文档的编辑&#xff0c;可以自定义制作PDF电子文档&#xf…

IP属地会随着人的移动而改变吗

在当今数字化时代&#xff0c;互联网已成为人们生活中不可或缺的一部分。无论是社交媒体的日常互动&#xff0c;还是在线购物、远程工作&#xff0c;IP地址作为网络身份的重要标识&#xff0c;扮演着举足轻重的角色。随着移动互联网技术的飞速发展&#xff0c;人们越来越多地在…

我的世界-与门、或门、非门等基本门电路实现

一、红石比较器 (1) 红石比较器结构 红石比较器有前端单火把、后端双火把以及两个侧端 其中后端和侧端是输入信号,前端是输出信号 (2) 红石比较器的两种模式 比较模式 前端火把未点亮时处于比较模式 侧端>后端 → 0 当任一侧端强度大于后端强度时,输出…

【大数据】机器学习------支持向量机(SVM)

支持向量机的基本概念和数学公式&#xff1a; 1. 线性可分的支持向量机 对于线性可分的数据集 &#xff0c;其中(x_i \in R^d) 是特征向量 是类别标签&#xff0c;目标是找到一个超平面 &#xff0c;使得对于所有 的样本 &#xff0c;对于所有(y_i -1) 的样本&#xff0c;…

RDD和DataFrame两种数据结构的对比

文章目录 1. 实战概述2. RDD&#xff08;弹性分布式数据集&#xff09;2.1 RDD概念2.2 RDD特点2.3 实战操作 3. DataFrame&#xff08;数据帧&#xff09;3.1 DataFrame概念3.2 DataFrame优点3.3 实战操作 4. 实战小结 1. 实战概述 今天我们将深入探讨 Apache Spark 中的两种核…

中职网络建设与运维ansible服务

ansible服务 填写hosts指定主机范围和控制节点后创建一个脚本&#xff0c;可以利用简化脚本 1. 在linux1上安装系统自带的ansible-core,作为ansible控制节点,linux2-linux7作为ansible的受控节点 Linux1 Linux1-7 Yum install ansible-core -y Vi /etc/ansible/hosts 添加…

Kibana 控制台中提供语义、向量和混合搜索

作者&#xff1a;来自 Elastic Mark_Laney 想要将常规 Elasticsearch 查询与新的 AI 搜索功能结合起来吗&#xff1f;那么&#xff0c;你不需要连接到某个第三方的大型语言模型&#xff08;LLM&#xff09;吗&#xff1f;不。你可以使用 Elastic 的 ELSER 模型来改进现有搜索&a…

多种 Docker 镜像拉取解决方案与实践

最近国内 Docker 镜像拉取不太通畅&#xff0c;尝试了几种镜像拉取的方式&#xff0c;写篇博客分享一下。 原以为只是 docker hub 被毙了&#xff0c;上机器一操作&#xff0c;官方的下载地址也被毙了&#xff0c;真是从源头解决问题。 不过还好目前还有其他源能用&#xff0…

2025边缘计算新年沙龙成功举办,共话边缘AI未来

1月11日下午&#xff0c;北京市海淀区中关村创业大街热闹非凡&#xff0c;以“云边腾跃&#xff0c;蛇启新航”为主题的 2025边缘计算新年沙龙 盛大举行。本次活动汇聚了边缘计算、人工智能以及云边协同领域的顶尖专家、学者和从业者&#xff0c;共同探讨技术前沿与实际应用场景…

使用redis-cli命令实现redis crud操作

项目场景&#xff1a; 线上环境上redis中的key影响数据展示&#xff0c;需要删除。但环境特殊没办法通过 redis客户端工具直连。只能使用redis-cli命令来实现。 操作步骤&#xff1a; 1、确定redis安装的服务器&#xff1b; 2、找到redis的安装目录下 ##找到redis安装目…

CentOS 下载软件时报Error: Failed to synchronize cache for repo ‘AppStream‘解决方法

下载软件时出现以下问题 直接把CentOS-AppStream.repo改个名字就行 cd /etc/yum.repos.d/ mv CentOS-AppStream.repo CentOS-AppStream.repo.bak就可以了 解决思路 把AI问遍&#xff0c;无人会&#xff0c;解决法 想要下载软件通通失败了&#xff0c;解决方法当然是问AI&am…

【深度学习】神经网络之Softmax

Softmax 函数是神经网络中常用的一种激活函数&#xff0c;尤其在分类问题中广泛应用。它将一个实数向量转换为概率分布&#xff0c;使得每个输出值都位于 [0, 1] 之间&#xff0c;并且所有输出值的和为 1。这样&#xff0c;Softmax 可以用来表示各类别的预测概率。 Softmax 函…

python管理工具:conda部署+使用

python管理工具&#xff1a;conda部署使用 一、安装部署 1、 下载 - 官网下载&#xff1a; https://repo.anaconda.com/archive/index.html - wget方式&#xff1a; wget -c https://repo.anaconda.com/archive/Anaconda3-2023.03-1-Linux-x86_64.sh2、 安装 在conda文件的…

当PHP遇上区块链:一场奇妙的技术之旅

PHP 与区块链的邂逅 在技术的广袤宇宙中&#xff0c;区块链技术如同一颗耀眼的新星&#xff0c;以其去中心化、不可篡改、透明等特性&#xff0c;掀起了一场席卷全球的变革浪潮。众多开发者怀揣着对新技术的热忱与探索精神&#xff0c;纷纷投身于区块链开发的领域&#xff0c;试…

unity——Preject3——开始界面拼面板

目录 1.创建panel&#xff0c;去掉panel自带的image&#xff0c;自己加一个image&#xff0c;使用锚点分配好 2.锚点&#xff08;快捷键点击后 ALTShift&#xff09; 锚点是什么&#xff1f; 锚点的实际例子 例子1&#xff1a;固定在父容器的中心 例子2&#xff1a;对齐到…

PyTorch使用教程(6)一文讲清楚torch.nn和torch.nn.functional的区别

torch.nn 和 torch.nn.functional 在 PyTorch 中都是用于构建神经网络的重要组件&#xff0c;但它们在设计理念、使用方式和功能上存在一些显著的区别。以下是关于这两个模块的详细区别&#xff1a; 1. 继承方式与结构 torch.nn torch.nn 中的模块大多数是通过继承 torch.nn…