一、代码功能与使用场景总结
这段代码是电商/商城系统中“用户地址删除”接口的自动化测试用例,基于 pytest 测试框架开发,结合 Allure 生成可视化测试报告、Loguru 记录日志、YAML 数据驱动实现多场景测试。
核心功能:自动测试“删除用户地址”接口的各种场景(如删除有效地址、删除不存在的地址、无效token删除地址等),验证接口返回的HTTP状态码、业务码、提示消息是否符合预期,同时记录关键日志和测试报告附件。
使用场景:商城项目的接口自动化测试(尤其是冒烟测试/地址模块专项测试),替代人工手动测试,快速验证地址删除接口的功能正确性,生成的Allure报告可直观展示测试步骤和结果。
二、核心模块拆分与逐模块解释
把整个代码比作「一位自动化测试员执行“删除地址”的测试流程」,拆分为5个核心步骤(模块),用生活化的比喻帮助理解:
模块1:前置准备(导入依赖 + 加载测试数据)
import pytest
import allure
from common.utils import handle_yaml
import os
from loguru import logger
# Load test data from YAML file
data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data", "useraddress_data.yaml")
datas = handle_yaml(data_path)功能解释:
导入测试所需的“工具包”:
pytest(测试框架,相当于测试员的工作手册)、allure(报告工具,相当于测试员的测试报告模板)、handle_yaml(读取YAML文件的工具,相当于测试员的测试用例表格)、os(路径工具,相当于找文件的导航)、logger(日志工具,相当于测试员的工作记录本);定位并读取YAML测试数据文件:找到项目中
data目录下的useraddress_data.yaml(存放所有删除地址的测试场景,比如“删有效地址”“删无效ID地址”),把数据加载到datas变量中。
类比:测试员先准备好测试用的“手册(pytest)”“报告模板(Allure)”“用例表格(YAML)”“记录本(logger)”,并从指定文件夹拿出写满测试场景的表格。
模块2:测试类与用例装饰器(定义测试规则 + 报告配置)
@allure.feature("User Address Management")
class TestUserAddressDelete:
@allure.story("Delete User Address Scenarios")
@pytest.mark.smoke
@pytest.mark.address
@pytest.mark.parametrize('user_address_data', datas['user_address_delete'])
@allure.title('{user_address_data[title]}')
def test_delete_user_address(self, user_address_data, user_business_flow, allure_response_attachments, login_token, setup_address_for_test):功能解释:
@allure.feature/@allure.story:给测试用例分类(Allure报告用),相当于测试员在报告上标注“测试大模块:用户地址管理”“测试子场景:删除地址场景”;@pytest.mark.smoke/@pytest.mark.address:给用例打标签,相当于测试员给用例贴“冒烟测试”“地址模块”的标签,方便后续只执行某类用例(比如只跑冒烟用例);@pytest.mark.parametrize:数据驱动核心,把YAML中user_address_delete下的所有测试场景(如3个场景)逐个传入user_address_data,相当于测试员按表格里的3条用例,逐条执行“删除地址”操作;@allure.title:用YAML中每个场景的title作为测试用例标题(如“确认删除用户地址成功”),报告中更易识别;函数参数(
user_business_flow/login_token等):pytest的fixture(夹具),相当于测试员提前准备好的“工具”——比如login_token是提前登录获取的有效令牌,setup_address_for_test是提前创建的测试地址(避免删真实数据)。
类比:测试员定好测试规则(只测地址删除、属于冒烟测试),把测试表格里的每条用例拆出来逐个执行,还提前准备好登录令牌、测试地址等“前置工具”。
模块3:测试数据预处理(提取预期值 + 占位符替换)
print(f"Debug: user_address_data: {user_address_data}")
expected_code = user_address_data['expected']['code']
expected_msg = user_address_data['expected']['msg']
expected_http_status_code = user_address_data['expected_http_status_code']
address_ids_from_data = user_address_data['address_ids']
token_from_data = user_address_data['token']
if token_from_data == '{valid_token}':
token_to_use = login_token
else:
token_to_use = token_from_data
# Replace placeholder with actual address ID if needed
if '{existing_address_id}' in address_ids_from_data:
actual_address_id = setup_address_for_test
address_ids = [actual_address_id]
else:
address_ids = address_ids_from_data功能解释:
提取预期值:从当前测试场景的YAML数据中,拿出“预期的业务码(如1000)、预期提示消息(如success)、预期HTTP状态码(如200)”,相当于测试员从表格里记下“这条用例要验证的结果”;
Token替换:如果YAML中写的是占位符
{valid_token},就替换成真实的登录令牌(login_token),否则用YAML里的无效token,相当于测试员按用例要求,选“有效钥匙(valid_token)”或“无效钥匙(invalid_token)”;地址ID替换:如果YAML中写的是占位符
{existing_address_id},就替换成提前创建的测试地址ID(setup_address_for_test),否则用YAML里的无效ID(如999999),相当于测试员按用例要求,选“真实存在的地址ID”或“不存在的地址ID”。
类比:测试员拿到一条用例后,先看清“要测什么(用有效/无效token、删存在/不存在的地址)”“要验证什么结果(预期返回success)”,并准备好对应的测试数据(替换掉占位的“假数据”)。
模块4:接口请求执行(调用删除接口 + Allure步骤记录)
with allure.step(f"尝试使用 token 删除用户地址"):
allure.attach(f"使用的 Token: {token_to_use[:10]}...", name="请求 Token", attachment_type=allure.attachment_type.TEXT)
allure.attach(f"请求地址ID: {address_ids}", name="请求地址ID", attachment_type=allure.attachment_type.TEXT)
response = user_business_flow.delete_user_address(token_to_use, address_ids)
allure_response_attachments(response)功能解释:
with allure.step:在Allure报告中记录“尝试删除地址”这个测试步骤,相当于测试员在报告里写“第一步:执行删除地址操作”;allure.attach:把请求用的Token、地址ID作为附件添加到报告中,相当于测试员把“用了什么钥匙、删了哪个地址”记在报告里,方便后续排查问题;调用删除接口:通过
user_business_flow.delete_user_address发送删除地址的请求,获取接口响应(response),相当于测试员在系统里操作“删除地址”,并拿到系统的返回结果;allure_response_attachments(response):把接口的完整响应(请求头、响应体等)添加到报告,相当于测试员把系统的“返回结果详情”贴到报告里。
类比:测试员执行“删除地址”操作,一边操作一边记笔记(Token、地址ID、系统返回结果),笔记会自动同步到测试报告里。
模块5:接口响应验证(断言 + 日志记录)
# 验证HTTP状态码
with allure.step("验证 HTTP 状态码"):
assert response.status_code == expected_http_status_code, \
f"预期 HTTP 状态码: {expected_http_status_code}, 实际: {response.status_code}"
response_json = response.json()
actual_code = int(response_json.get('code')) if response_json.get('code') is not None else None
actual_msg = response_json.get('message')
# 验证业务返回码
with allure.step("验证业务返回码"):
logger.info(f"验证业务返回码 - 预期: {expected_code}, 实际: {actual_code}")
assert actual_code == expected_code, \
f"预期业务返回码: {expected_code}, 实际: {actual_code}"
# 验证业务返回消息
with allure.step("验证业务返回消息"):
logger.info(f"验证业务返回消息 - 预期: {expected_msg}, 实际: {actual_msg}")
assert actual_msg == expected_msg, \
f"预期业务返回消息: {expected_msg}, 实际: {actual_msg}"
# 验证成功删除时data字段
if expected_code == 1000 and expected_msg == "success":
with allure.step("验证返回数据为 None 或空"):
assert response_json.get('data') is None or response_json.get('data') == {}, \
f"预期 data 字段为 None 或空, 实际为 {response_json.get('data')}"功能解释:
验证HTTP状态码:检查接口返回的HTTP状态码(如200/401)是否和预期一致,相当于测试员核对“系统是否正常接收请求(200=成功接收,401=未登录)”;
解析响应数据:把接口返回的JSON格式响应转成Python字典,提取实际的业务码(
actual_code)和提示消息(actual_msg),相当于测试员看懂系统返回的“结果代码”和“提示语”;验证业务码/消息:用
assert断言实际结果和预期一致,同时用logger.info记录验证过程(日志里能看到预期/实际值),相当于测试员核对“系统返回的结果是否和表格里的预期一致”,并把核对过程记在工作记录本(日志)上;额外验证成功场景的data字段:如果是成功删除的场景,验证
data字段为None/空(因为删除接口成功后通常无数据返回),相当于测试员额外核对“成功删除后,系统没有返回多余数据”。
类比:测试员拿到系统的返回结果后,逐条核对:“请求是否正常接收(HTTP状态码)”“结果是否符合预期(业务码/消息)”“成功删除后是否没有多余数据(data字段)”,核对不通过就标注失败,同时把核对过程记在记录本上。