接口自动化测试(python+pytest+requests)
Requests库是python中的“浏览器”,基于urllib的HTTP库安装/验证requests:命令行终端分别输入 pip install requests / pip show requests操作步骤:导包、发送接口请求、查看响应结果Requests发送请求requests.请求方法(url, params=None, data=None, json=None, headers=Non
一、选取自动化测试用例
- 优先级高:先实现业务流程用例、后实现单接口用例
- 功能较稳定的接口优先开展测试用例脚本的实现
二、搭建自动化测试环境
- 核心技术:编程语言:python;测试框架:pytest;接口请求:requests
- 安装/验证requests:命令行终端分别输入 pip install requests / pip show requests
三、搭建自动化测试框架
1. 接口自动化框架
2. 接口自动化框架设计思路
3. 搭建基础框架-定义项目目录结构
四、代码实现自动化
1、业务接口测试
1. Requests库
-
Requests库是python中的“浏览器”,基于urllib的HTTP库
-
安装/验证requests:命令行终端分别输入 pip install requests / pip show requests
-
操作步骤:导包、发送接口请求、查看响应结果
-
Requests发送请求
requests.请求方法(url, params=None, data=None, json=None, headers=None, files=None)
说明:- 常见的请求方法:get/post/put/delete
- url:请求的url地址 (字符串)
- params:请求的查询参数 (字典)
- data:请求体为form表单的参数 (字典)
- json:请求体为json的参数 (字典)
- headers:请求头参数 (字典)
- filse:上传文件,类型为multipart/form-data (字典) filse={"参数/file",上传文件二进制数据}
详细参考:Python中requests库_python requests-CSDN博客
-
Requests查看响应
import requests
url = 'http://kdtx-test.itheima.net/api/captchaImage'
response = requests.get(url)
print(response.json())
2. 接口对象封装的核心思想 (代码分层思想)
- 接口对象层(重点关注接口封装调用)
登录接口:
# 接口封装层,重点是依据接口文档封装接口信息,目录:api/login.py
# 需要使用的测试数据是从测试用例传递的,接口方法被调用是需要返回对应的响应结果
import requests
class LoginAPI:
url_verify = 'http://kdtx-test.itheima.net/api/captchaImage'
url_login = "http://kdtx-test.itheima.net/api/login"
# 初始化
def __init__(self):
pass
# 定义获取验证码方法
def get_verify_code(self):
return requests.get(url=self.url_verify)
# 定义登录方法
def login(self, login_param: dict):
return requests.post(url=self.url_login, json=login_param)
课程接口:
# 接口封装层,重点是依据接口文档封装接口信息,目录:api/course.py
# 需要使用的测试数据是从测试用例传递的,接口方法被调用是需要返回对应的响应结果
import requests
class CourseAPI:
# 初始化
def __init__(self, url_add_course):
self.url_add_course = url_add_course
# 定义添加课程方法 token需登录后才拿到值
def add_course(self, request_param, token):
# 请求头携带鉴权信息 "Content-Type": "application/json"因为参数已经传的是json 会默认识别格式,所以不用另外传
headers = {
"Authorization": token
}
return requests.post(url=self.url_add_course, json=request_param, headers=headers)
合同接口(文件上传)
# 接口封装层,重点是依据接口文档封装接口信息,目录:api/contract.py
# 需要使用的测试数据是从测试用例传递的,接口方法被调用是需要返回对应的响应结果
import requests
class ContractAPI:
# 初始化
def __init__(self, url_upload):
self.url_upload = url_upload
# 合同上传接口
def upload_contract(self, contract_data, token):
headers = {
"Authorization": token
}
files = {
"file": contract_data
}
return requests.post(url=self.url_upload, files=files, headers=headers)
- 测试脚本层(重点关注测试数据准备、断言及业务处理等)
模拟业务流程(验证码-登录-新增课程-上传合同)涉及接口的自动化测试脚本
注意:需安装pytest且不能有__init__方法 才能识别是测试类
测试类规则:
- 1.模块名必须以test_开头或者_test结尾
- 2.测试类必须以Test开头,并且不能有init方法
- 3.测试用例必须以test开头
测试类可以看方法的详细执行情况
# 测试脚本层 目录 script/test03_contract_business.py
# 验证码-登录-上传合同-新增合同 合同新增业务流程涉及接口的自动化测试脚本
# 导包 自定义的先from到文件下 在import对应的类
from api.login import LoginAPI
from api.course import CourseAPI
from api.contract import ContractAPI
# 创建测试类
class TestContractBusiness:
# 链接来自b站黑马的视频
__url_add_course = "http://kdtx-test.itheima.net/api/clues/course"
__url_upload = "http://kdtx-test.itheima.net/api/common/upload"
__url_add_contract = "http://kdtx-test.itheima.net/api/contract"
token = None
# # 初始化 测试类不能有该方法 初始的逻辑放在前置处理方法里
# def __init__(self):
# self.login_api = LoginAPI()
# self.course_api = CourseAPI(self.__url_add_course)
# self.contract_api = ContractAPI(self.__url_upload)
# 前置处理
def setup(self):
# 实例化接口对象
self.login_api = LoginAPI(self.__url_verify, self.__url_login)
self.course_api = CourseAPI(self.__url_add_course)
self.contract_api = ContractAPI(self.__url_upload, self.__url_add_contract)
# 后置处理
def teardown(self):
pass
# 登录成功
def test01_login_success(self):
# 获取验证码
res_v = self.login_api.get_verify_code()
print(res_v.json())
print(res_v.json().get("uuid"))
# 登录
login_param = {
"username": "admin",
"password": "HM_2023_test",
"code": 2,
"uuid": res_v.json().get("uuid")
}
res_l = self.login_api.login(login_param=login_param)
# 提取登录成功之后的token数据并保存在类的属性中
# 相当于java中类的静态属性赋值,直接通过类去给属性赋值,通过类去获取属性值
TestContractBusiness.token = res_l.json().get("token")
print(res_l.json())
# return res_l
# 添加课程
def test02_add_course(self):
# # 先登录拿token
# res_login_success = self.test01_login_success()
# print(res_login_success.json())
# token = res_login_success.json().get("token")
# ====== token 直接取类的属性 调登录方法时赋了值
add_course_param = {
"name": "好的课",
"subject": "5",
"price": 899,
"applicablePerson": "2",
"info": "测试测试"
}
res_c = self.course_api.add_course(request_param=add_course_param, token=TestContractBusiness.token)
print(res_c.json())
# return res_c
# 上传合同
def test03_upload_contract(self):
# 读取合同文件二进制数据 第二个参数 rb
contract_data = open("../data/test.pdf", "rb")
res = self.contract_api.upload_contract(contract_data=contract_data, token=TestContractBusiness.token)
print(res.json())
# return res
# 新增合同
def test04_add_contract(self):
# contractNo 合同编号 数据唯一
add_contract_param = {
"name": "test",
"phone": "12345678901",
"contractNo": "HT2023597",
"subject": "6",
"courseId": "468",
"channel": "0",
"activityId": 77,
"fileName": "xxx"
}
res = self.contract_api.add_contract(request_param=add_contract_param, token=TestContractBusiness.token)
print(res.json())
# return res
结果:
2、单接口测试
- 登录接口单接口测试
断言:按照测试用例预期结果进行断言
相等断言:assert 预期结果 == 实际结果
包含断言:assert 预期结果 in 实际结果
# 登录单接口测试:测试登录接口的测试用例(每个测试用例一个测试方法,使用断言的方式验证预期结果)
from api.login import LoginAPI
class TestLoginAPI:
# 前置处理
# uuid = None
uuid = None
def setup(self):
# 实例化接口类
self.login_api = LoginAPI()
# 获取验证码
res = self.login_api.get_verify_code()
# 提取验证接口返回的uuid参数值 类的属性保存
print("uuid:", res.json().get("uuid"))
TestLoginAPI.uuid = res.json().get("uuid")
# 后置处理
def teardown(self):
pass
# 用例一:登录成功
def test01_success(self):
login_param = {
"username": "admin",
"password": "HM_2023_test",
"code": 2,
"uuid": TestLoginAPI.uuid
}
response = self.login_api.login(login_param)
print(response.json())
# 断言测试用例的预期结果
# 断言响应状态码
assert 200 == response.status_code
# 断言响应数据包含‘成功’
assert '成功' in response.text
# 断言响应jsons数据中的code值
assert 200 == response.json().get("code")
# 用例二:登录失败(用户名为空)
def test02_without_username(self):
login_param = {
"username": "",
"password": "HM_2023_test",
"code": 2,
"uuid": TestLoginAPI.uuid
}
response = self.login_api.login(login_param)
print(response.json())
# 断言测试用例的预期结果
# 断言响应状态码
assert 200 == response.status_code
# 断言响应数据包含‘成功’
assert '错误' in response.text
# 断言响应jsons数据中的code值
assert 500 == response.json().get("code")
# 用例三:登录失败(用户不存在)
def test03_username_not_exist(self):
login_param = {
"username": "admin123",
"password": "HM_2023_test",
"code": 2,
"uuid": TestLoginAPI.uuid
}
response = self.login_api.login(login_param)
print(response.json())
# 断言测试用例的预期结果
# 断言响应状态码
assert 200 == response.status_code
# 断言响应数据包含‘成功’
assert '错误' in response.text
# 断言响应jsons数据中的code值
assert 500 == response.json().get("code")
- 数据驱动
以测试数据驱动脚本执行,维护焦点从脚本转向测试数据的一种自动化测试设计模式。
应对场景:一个接口有多条测试用例,每个测试用例写一个测试方法去断言比较繁琐
- json文件测试数据
[
{
"username": "admin",
"password": "HM_2023_test",
"status": 200,
"msg": "成功",
"code": 200
},
{
"username": "",
"password": "HM_2023_test",
"status": 200,
"msg": "错误",
"code": 500
},
{
"username": "admin123",
"password": "HM_2023_test",
"status": 200,
"msg": "错误",
"code": 500
}
]
- 代码实现
# 数据驱动单接口测试
# 测试数据 含入参以及预期响应 注解最终入参的数据类型为:列表[字典]
import json
import pytest
from api.login import LoginAPI
# 测试数据 后改成直接从json文件读取 最终格式保持为 列表[字典]
# login_data_test = [
# ("admin", "HM_2023_test", 200, "成功", 200),
# ("", "HM_2023_test", 200, "错误", 500),
# ("admin123", "HM_2023_test", 200, "错误", 500),
# ]
# json文件读取测试数据
def build_login_data(filename):
# 数据格式[(),()]
result = []
with open(filename, "r", encoding='UTF-8') as data:
login_params = json.loads(data.read())
for param in login_params:
# 转换数据格式 [{},{}] -> [(),()]
dict_data = (
param.get("username"),
param.get("password"),
param.get("status"),
param.get("msg"),
param.get("code"),
)
result.append(dict_data)
print("result", result)
return result
class TestLoginAPI:
# 前置处理
uuid = None
def setup(self):
# 实例化接口类
self.login_api = LoginAPI()
# 获取验证码
res = self.login_api.get_verify_code()
# 提取验证接口返回的uuid参数值 类的属性保存
print("uuid:", res.json().get("uuid"))
TestLoginAPI.uuid = res.json().get("uuid")
# 后置处理
def teardown(self):
pass
# 数据驱动登录接口测试
@pytest.mark.parametrize("username, password, status, msg, code", build_login_data("../data/login.json"))
def test_login(self, username, password, status, msg, code):
login_param = {
"username": username,
"password": password,
"code": 2,
"uuid": TestLoginAPI.uuid
}
response = self.login_api.login(login_param)
print(response.json())
# 断言测试用例的预期结果
# 断言响应状态码
assert status == response.status_code
# 断言响应数据包含‘成功’
assert msg in response.text
# 断言响应jsons数据中的code值
assert code == response.json().get("code")
- 结论
- config.py配置文件
存放被测项目基本信息,如URL地址等
- 配置环境的域名和项目的根路径以及项目中使用的公共数据,代码中获取如下:
import config
print(config.BASE_URL)
print(config.BASE_PATH)
五、输出Allure测试报告
Allure:支持多种开发语言,如java、python等
帮助文档:Allure Report Docs — Introduction
操作步骤:
- 生成测试结果文件(json文件)
- 安装 pip install allure-pytest
- 在pytest.ini件中的命令行参数加上如下代码设定:
# pytest配置文件 按照实际目录调整通配符 pytest.ini
[pytest]
# 结果文件在哪个目录下
addopts=-s --alluredir report
# 测试文件所在位置
testpaths=./script
# 在测试文件目录下哪些文件/类/方法需要被执行 通配符
python_files=test*.py
python_classes=Test*
python_functions =test*
- 编写好测试脚本后,在命令行行中运行pytest(直接在终端输入pytest即可)
- 程序运行结束后,会在项目的report目录中生成一些json文件
- 使用allure命令生成在线报告
Releases · allure-framework/allure2 · GitHub
终端命令行运行:allure serve report
报错:修改环境变量之后需要重新启动pycharm
allure : 无法将“allure”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
所在位置 行:1 字符: 1
+ allure serve report
+ ~~~~~~
+ CategoryInfo : ObjectNotFound: (allure:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
这是我整理的《2024最新Python自动化测试全套教程》,以及配套的接口文档/项目实战【网盘资源】,需要的朋友可以下方视频的置顶评论获取。肯定会给你带来帮助和方向。
【已更新】B站讲的最详细的Python接口自动化测试实战教程全集(实战最新版)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)