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

使用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==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.kler.cn/a/506171.html

相关文章:

  • 《探索烟雾目标检测开源项目:技术与应用的深度剖析》
  • Redis 3.2.1在Win10系统上的安装教程
  • http转化为https生成自签名证书
  • SQL Prompt 插件
  • vue项目引入阿里云svg资源图标
  • Docker
  • 浅谈云计算14 | 云存储技术
  • Windows图形界面(GUI)-QT-C/C++ - QT 对话窗口
  • python flask简单实践
  • 谷歌浏览器的兼容性与性能优化策略
  • MySQL程序之:使用选项设置程序变量
  • 滚动字幕视频怎么制作
  • [Qt]窗口-QMainWindow类-QMenuBar、QToolBar、QStatusBar、QDockWidget控件
  • 运营媒体账号为什么需要住宅IP
  • 理解Spark中运行程序时数据被分区的过程
  • unity——Preject3——UI管理器
  • 【华为路由/交换机的ftp文件操作】
  • CSS的小知识
  • 蓝桥杯刷题第一天——判断闰年
  • 【k8s面试题2025】2、练气初期
  • 手摸手实战前端项目CI CD
  • 用 Python 自动化处理日常任务
  • 解决 chls.pro/ssl 无法进入问题
  • 【Rust自学】13.2. 闭包 Pt.2:闭包的类型推断和标注
  • 麒麟系统WPS提示字体缺失问题
  • 力扣 查找元素的位置