【实战】宠物商店接口自动化测试实战
宠物商店接口自动化测试实战
被测产品
- PetStore 宠物商城:
- 一个在线的小型的商城。
- 主要提供了增删查改等操作接口。
- 结合 Swagger 实现了接口的管理。
需求说明
- 完成宠物商城宠物查询功能接口自动化测试。
- 编写自动化测试脚本。
- 完成断言。
相关知识点
形式 | 章节 | 描述 |
---|---|---|
知识点 | 接口请求方法 | http 接口请求方法构造 |
知识点 | 接口请求参数 | http 接口请求参数构造 |
知识点 | 接口请求体-json | http 接口请求体为 json 格式 |
知识点 | 接口响应断言 | http 接口响应状态码断言 |
实战思路
宠物商店需求分析
- 被测产品:宠物商店系统 - 查询宠物信息
- 宠物商店接口文档:https://petstore.swagger.io/
接口测试用例设计
- 宠物查询单接口用例
编写接口自动化测试脚本思路
- 查询宠物信息。
编写自动化测试脚本
class TestPetstorePetsearch:
def setup_class(self):
# 定义接口请求 URL
self.base_url = "https://petstore.swagger.io/v2/pet"
self.search_url = self.base_url + "/findByStatus"
def test_search_pet(self):
# 查询接口请求参数
params = {
"status": "available"
}
# 发出查询请求
r = requests.get(self.search_url, params=params)
# 状态断言
assert r.status_code == 200
# 业务断言
assert r.json() != []
脚本优化 - 添加日志
- 新建日志配置。
- 在用例中使用配置好的日志实例。
创建 utils 包,包下创建 log_util.py 文件。
# 配置日志
import logging
import os
from logging.handlers import RotatingFileHandler
# 绑定绑定句柄到logger对象
logger = logging.getLogger(__name__)
# 获取当前工具文件所在的路径
root_path = os.path.dirname(os.path.abspath(__file__))
# 拼接当前要输出日志的路径
log_dir_path = os.sep.join([root_path, '..', f'/logs'])
if not os.path.isdir(log_dir_path):
os.mkdir(log_dir_path)
# 创建日志记录器,指明日志保存路径,每个日志的大小,保存日志的上限
file_log_handler = RotatingFileHandler(os.sep.join([log_dir_path, 'log.log']), maxBytes=1024 * 1024, backupCount=10)
# 设置日志的格式
date_string = '%Y-%m-%d %H:%M:%S'
formatter = logging.Formatter(
'[%(asctime)s] [%(levelname)s] [%(filename)s]/[line: %(lineno)d]/[%(funcName)s] %(message)s ', date_string)
# 日志输出到控制台的句柄
stream_handler = logging.StreamHandler()
# 将日志记录器指定日志的格式
file_log_handler.setFormatter(formatter)
stream_handler.setFormatter(formatter)
# 为全局的日志工具对象添加日志记录器
# 绑定绑定句柄到logger对象
logger.addHandler(stream_handler)
logger.addHandler(file_log_handler)
# 设置日志输出级别
logger.setLevel(level=logging.INFO)
然后在脚本中把 print
替换为 logger.info
class TestPetstorePetsearch:
def setup_class(self):
# 定义接口请求 URL
self.base_url = "https://petstore.swagger.io/v2/pet"
self.search_url = self.base_url + "/findByStatus"
def test_search_pet(self):
# 查询接口请求参数
params = {
"status": "available"
}
# 发出查询请求
r = requests.get(self.search_url, params=params)
# 查看接口响应
logger.info(r.text)
添加断言
class TestPetstorePetsearch:
def setup_class(self):
# 定义接口请求 URL
self.base_url = "https://petstore.swagger.io/v2/pet"
self.search_url = self.base_url + "/findByStatus"
def test_search_pet(self):
# 查询接口请求参数
params = {
"status": "available"
}
# 发出查询请求
r = requests.get(self.search_url, params=params)
# 查看接口响应
logger.info(r.text)
# 状态断言
assert r.status_code == 200
# 业务断言
assert r.json() != []
# 响应返回的是一个列表,判断列表中第一个元素中是否包含 id 这个 key
assert "id" in r.json()[0]
脚本优化 - 参数化
- 使用 pytest parametrize 装饰器实现宠物状态的参数化。
class TestPetstorePetsearch:
def setup_class(self):
# 定义接口请求 URL
self.base_url = "https://petstore.swagger.io/v2/pet"
self.search_url = self.base_url + "/findByStatus"
@pytest.mark.parametrize("status",
["available", "pending", "sold"],
ids=["available_pets", "pending_pets", "sold_pets"]
)
def test_search_pet_by_param(self, status):
# 查询接口请求参数
parmas = {
"status": status
}
# 添加日志
logger.info(f"查询状态为 {status} 的宠物信息")
# 发出查询请求
r = requests.get(self.search_url, params=parmas)
logger.info(f"查询接口响应为:{r.text}")
# 状态断言
assert r.status_code == 200
# 业务断言
assert r.json() != []
assert "id" in r.json()[0]
异常场景覆盖
class TestPetstorePetsearch:
def setup_class(self):
# 定义接口请求 URL
self.base_url = "https://petstore.swagger.io/v2/pet"
self.search_url = self.base_url + "/findByStatus"
@pytest.mark.parametrize("status",
["petstatus", "", 12345,],
ids=["wrong_value", "none_str", "number"]
)
def test_search_pet_failure(self, status):
# 查询接口请求参数
parmas = {
"status": status
}
# 添加日志
logger.info(f"查询状态为 {status} 的宠物信息")
# 发出查询请求
r = requests.get(self.search_url, params=parmas)
logger.info(f"查询接口响应为:{r.text}")
# 状态断言
assert r.status_code == 200
# 业务断言
assert r.json() == []
def test_search_pet_none_param(self):
# 发出查询请求
r = requests.get(self.search_url)
logger.info(f"查询接口响应为:{r.text}")
# 状态断言
assert r.status_code == 200
# 业务断言
assert r.json() == []
def test_search_pet_wrong_param(self):
# 查询接口请求参数
parmas = {
"key": "available"
}
# 发出查询请求
r = requests.get(self.search_url, params=parmas)
logger.info(f"查询接口响应为:{r.text}")
# 状态断言
assert r.status_code == 200
# 业务断言
assert r.json() == []
生成测试报告
- 安装 allure 相关依赖。
给测试脚本填写一些描述信息。
@allure.feature("宠物搜索接口")
class TestPetstorePetsearch:
def setup_class(self):
# 定义接口请求 URL
self.base_url = "https://petstore.swagger.io/v2/pet"
self.search_url = self.base_url + "/findByStatus"
@pytest.mark.parametrize("status",
["available", "pending", "sold"],
ids=["available_pets", "pending_pets", "sold_pets"]
)
@allure.story("冒烟用例")
def test_search_pet_by_param(self, status):
# 查询接口请求参数
@pytest.mark.parametrize("status",
["petstatus", "", 12345,],
ids=["wrong_value", "none_str", "number"]
)
@allure.story("status 传入错误的值")
def test_search_pet_failure(self, status):
# 查询接口请求参数
@allure.story("不传 status 参数")
def test_search_pet_none_param(self):
# 发出查询请求
@allure.story("传入非 status 参数")
def test_search_pet_wrong_param(self):
# 查询接口请求参数
添加好之后,执行这个测试脚本。
# 生成报告信息
pytest -vs test_petclinic_petsearch.py --alluredir=./report --clean-alluredir
# 生成报告在线服务,查看报告
allure serve ./report/
总结
- 通过 Swagger 文档获取接口信息。
- 使用 Requests 发出携带请求参数的 GET 请求。
- 断言响应符合是否符合预期。
- 添加 Log 日志。
- 使用参数化方式实现一条用例可执行多个测试数据。
- 生成 Allure 测试报告。