一、选取自动化测试用例
- 优先级高:先实现业务流程用例、后实现单接口用例
- 功能较稳定的接口优先开展测试用例脚本的实现
二、搭建自动化测试环境
- 核心技术:编程语言: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 = Noneuuid = 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 resultclass TestLoginAPI:
# 前置处理
uuid = Nonedef 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
报错:修改环境变量之后需要重新启动pycharmallure : 无法将"allure"项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
所在位置 行:1 字符: 1- allure serve report
-
+ CategoryInfo : ObjectNotFound: (allure:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException
这是我整理的**《2024最新Python自动化测试全套教程》** ,以及配套的接口文档/项目实战**【网盘资源】** ,需要的朋友可以下方视频的置顶评论获取。肯定会给你带来帮助和方向。
【已更新】B站讲的最详细的Python接口自动化测试实战教程全集(实战最新版)