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

一、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==200print(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==200logging.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==codelogging.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==201logging.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==200logging.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==200logging.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==200logging.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.rhkb.cn/news/3150.html

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

相关文章

【Rust自学】13.2. 闭包 Pt.2:闭包的类型推断和标注

13.2.0. 写在正文之前 Rust语言在设计过程中收到了很多语言的启发,而函数式编程对Rust产生了非常显著的影响。函数式编程通常包括通过将函数作为值传递给参数、从其他函数返回它们、将它们分配给变量以供以后执行等等。 在本章中,我们会讨论 Rust 的一…

无人机技术架构剖析!

一、飞机平台系统 飞机平台系统是无人机飞行的主体平台,主要提供飞行能力和装载功能。它由机体结构、动力装置、电气设备等组成。 机体结构:无人机的机身是其核心结构,承载着其他各个组件并提供稳定性。常见的机身材料包括碳纤维、铝合金、…

Axios封装一款前端项目网络请求实用插件

前端项目开发非常经典的插件axios大家都很熟悉,它是一个Promise网络请求库,可以用于浏览器和 node.js 支持的项目中。像一直以来比较火的Vue.js开发的几乎所有项目网络请求用的都是axios。那么我们在实际的项目中,有时候为了便于维护、请求头…

【c++继承篇】--继承之道:在C++的世界中编织血脉与传承

目录 引言 一、定义二、继承定义格式2.1定义格式2.2继承关系和访问限定符2.3继承后子类访问权限 三、基类和派生类赋值转换四、继承的作用域4.1同名变量4.2同名函数 五、派生类的默认成员构造函数5.1**构造函数调用顺序:**5.2**析构函数调用顺序:**5.3调…

LDD3学习8--linux的设备模型(TODO)

在LDD3的十四章,是Linux设备模型,其中也有说到这个部分。 我的理解是自动在应用层也就是用户空间实现设备管理,处理内核的设备事件。 事件来自sysfs和/sbin/hotplug。在驱动中,只要是使用了新版的函数,相应的事件就会…

Python基于Django的图像去雾算法研究和系统实现(附源码,文档说明)

博主介绍:✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&#x1f3…

Python爬虫(5) --爬取网页视频

文章目录 爬虫爬取视频 指定url发送请求 UA伪装请求页面 获取想要的数据 解析定位定位音视频位置 存放视频完整代码实现总结 爬虫 Python 爬虫是一种自动化工具,用于从互联网上抓取网页数据并提取有用的信息。Python 因其简洁的语法和丰富的库支持(如…

从AI原理到模型演进及代码实践 的学习二

参考:全面解析:从AI原理到模型演进及代码实践-CSDN博客 训练过程 Transformer仅一个Encoder模块就可以工作,可以处理信息抽取、识别、主体识别等任务,比如 BERT(Bidirectional Encoder Representations from Transfor…

利用EXCEL进行XXE攻击

0X00 前言 CTF 选手都清楚我们像 word 文档格式改成 zip 格式后,再解压缩可以发现其中多数是描述工作簿数据、元数据、文档信息的 XML 文件。实际上,与所有 post-Office 2007 文件格式一样,现代 Excel 文件实际上只是 XML 文档的 zip 文件。…

在Mac mini上实现本地话部署AI和知识库

在Mac mini上实现本地话部署AI和知识库 硬件要求:大模型AI,也叫LLM,需要硬件支持,常见的方式有2种:一种是采用英伟达之类支持CUDA库的GPU芯片或者专用AI芯片;第二种是采用苹果M系列芯片架构的支持统一内存架…

鸿蒙UI(ArkUI-方舟UI框架)-开发布局

文章目录 开发布局1、布局概述1)布局结构2)布局元素组成3)如何选择布局4)布局位置5)对子元素的约束 2、构建布局1)线性布局 (Row/Column)概述布局子元素在排列方向上的间距布局子元素在交叉轴上的对齐方式(…

指针的进阶

指针的主题,我们在初级阶段的《指针》章节已经接触过了,我们知道了指针的概念: 1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。 2. 指针的大小是固定的4/8个字节(32位平台/64位平台&#xff0…

B站评论系统的多级存储架构

1. 背景 评论是 B站生态的重要组成部分,涵盖了 UP 主与用户的互动、平台内容的推荐与优化、社区文化建设以及用户情感满足。B站的评论区不仅是用户互动的核心场所,也是平台运营和用户粘性的关键因素之一,尤其是在与弹幕结合的情况下&#xf…

若依分页插件失效问题

若依对数据二次处理导致查询total只有十条的问题处理办法_若依分页查询total-CSDN博客

css盒子水平垂直居中

目录 1采用flex弹性布局: 2子绝父相margin:负值: 3.子绝父相margin:auto: 4子绝父相transform: 5通过伪元素 6table布局 7grid弹性布局 文字 水平垂直居中链接:文字水平垂直居中-CSDN博客 以下为盒子…

Golang Gin系列-3:Gin Framework的项目结构

在Gin教程的第3篇,我们将讨论如何设置你的项目。这不仅仅是把文件扔得到处都是,而是要对所有东西的位置做出明智的选择。相信我,这些东西很重要。如果你做得对,你的项目会更容易处理。当你以后不再为了找东西或添加新功能而绞尽脑…

03JavaWeb——Ajax-Vue-Element(项目实战)

1 Ajax 1.1 Ajax介绍 1.1.1 Ajax概述 我们前端页面中的数据,如下图所示的表格中的学生信息,应该来自于后台,那么我们的后台和前端是互不影响的2个程序,那么我们前端应该如何从后台获取数据呢?因为是2个程序&#xf…

【无法下载github文件】虚拟机下ubuntu无法拉取github文件

修改hosts来进行解决。 步骤一:打开hosts文件 sudo vim /etc/hosts步骤二:查询 github.com的ip地址 https://sites.ipaddress.com/github.com/#ipinfo将github.com的ip地址添加到hosts文件末尾,如下所示。 140.82.114.3 github.com步骤三…

【Idea启动项目报错NegativeArraySizeException】

项目场景: Idea启动项目报错(打包不报错),项目在服务器部署运行没有问题,尝试了重启idea、重启电脑、maven clean/install 都不行 maven-resources-production:sample: java.lang.NegativeArraySizeException: -5833…

【 MySQL 学习2】常用命令

文章目录 一、基础命令1.1、登录1.2 、退出1.3、查看数据库中有哪些数据库1.4 、选择使用的数据库1.5、创建数据库1.6 查看哪个数据库下有哪些表 二、SQL语句的分类2.1 DQL 数据查询语言2.2 DML 数据操作语言2.3 DDL 数据定义语言2.4 TCL 事物控制语言2.5 DCL 数据控制语言 三、…