1. 测试概述1.1 测试背景星阅书城平台的登录、用户管理、商品与订单等接口是业务主链路用户必须先登录拿到Token凭证才能新增、修改用户下单链路则要按 商品列表 → 商品详情 → 提交订单 → 订单支付 → 校验订单状态 的顺序逐级依赖上一步的返回值。这类接口的特点是接口数量多、参数以表单和 JSON 混合提交登录、用户管理是application/x-www-form-urlencoded商品与订单是application/json接口之间存在强数据依赖token、商品 ID、订单号要在用例之间传递异常分支容易被漏测缺 token、缺必填参数、ID 不存在、密码错误等人工回归一次要重复造数据、重复登录成本高且容易漏。为把这条主链路的回归从「手工点一遍」变成「一条命令跑完并自动通知结果」搭建了本套接口自动化测试框架 用例数据与代码分离YAML 数据驱动断言、请求、日志、报告、通知全部封装复用既能在本地一条命令执行也能接入 Jenkins 持续集成每次构建自动产出 Allure 报告并推送飞书通知。1.2 测试目标序号目标衡量方式1验证登录接口三种分支的正确性成功 / 账号密码错 / 缺必填参数并保证成功时下发可用凭证登录 4 条用例全部通过响应字段逐项断言2验证用户管理单接口的正向与异常分支新增、修改、删除、查询用户模块 10 条用例全部通过异常分支均命中预期提示语3验证「商品列表 → 详情 → 下单 → 支付 → 订单状态」整条业务链路能串起来跑通业务场景 5 条用例按顺序全部通过链路变量正确传递4验证接口关联能力上一步的返回值能自动传给下一步无需人工改数据extract/extract_list${}占位符生效链路无需硬编码5建立可持续回归的工程能力一条命令执行、自动出报告、自动通知、可接入 CIpytest一条命令跑完 19 条Jenkins 构建成功并产出 Allure 报告 飞书通知6通过自动化用例反过来发现被测系统的问题见第 6 章「缺陷分析」1.3 测试范围本次覆盖3 个模块 / 9 个接口 / 19 条用例模块接口方法传参方式用例数登录/dar/user/loginPOSTform 表单4用户管理单接口/dar/user/addUserPOSTform 表单4用户管理单接口/dar/user/updateUserPOSTform 表单1用户管理单接口/dar/user/deleteUserPOSTform 表单4用户管理单接口/dar/user/queryUserPOSTform 表单1下单流程业务链路/coupApply/cms/goodsListGETURL 参数1下单流程业务链路/coupApply/cms/productDetailPOSTJSON1下单流程业务链路/coupApply/cms/placeAnOrderPOSTJSON1下单流程业务链路/coupApply/cms/orderPayPOSTJSON1下单流程业务链路/coupApply/cms/checkOrderStatusPOSTJSON12.接口测试用例从单接口、业务逻辑接口、接口安全性多方面设计接口测试用例。单接口测试用例考虑正向覆盖所有的必选参数、组合非必选参数以及边界值。反向考虑空数据和特殊值。业务逻辑接口测试用例注意上下接口之间有关联参数的接口同时也需要考虑接口的安全性未登录、特殊权限用户、参数加密等3.接口自动化测试框架设计3.1测试框架PythonPytestRequests3.2项目结构3.3环境依赖3.4yaml文件设计测试用例选择YAML文件管理接口地址、请求方式、请求头、请求参数、变量提取规则和预期结果。以用户下单的接口为例- case_id: order_create_001 title: 已登录用户购买一本已上架图书 request: method: POST path: /api/orders headers: Authorization: Bearer ${user_token} json: book_id: ${book_id} quantity: 1 validate: - eq: [status_code, 200] - eq: [body.code, 0] - eq: [body.data.status, PENDING_PAYMENT] extract: order_id: $.data.id5.核心功能5.1请求封装请求封装的目的是统一处理基础地址、超时时间、公共请求头、日志、报告附件和异常信息而不是把业务断言全部塞进一个方法。import json import requests import allure SENSITIVE_FIELDS { password, token, access_token, refresh_token, authorization, cookie, set-cookie, } def mask(data): if isinstance(data, dict): return { key: *** if key.lower() in SENSITIVE_FIELDS else mask(value) for key, value in data.items() } if isinstance(data, list): return [mask(item) for item in data] return data class ApiClient: def __init__(self, base_url, timeout10): self.base_url base_url.rstrip(/) self.timeout timeout self.session requests.Session() def request(self, method, path, **kwargs): url f{self.base_url}/{path.lstrip(/)} kwargs.setdefault(timeout, self.timeout) response self.session.request(method.upper(), url, **kwargs) request_info { method: method.upper(), url: url, headers: mask(kwargs.get(headers, {})), json: mask(kwargs.get(json, {})), } allure.attach( json.dumps(request_info, ensure_asciiFalse, indent2), 请求信息, allure.attachment_type.JSON, ) try: response_body json.dumps( mask(response.json()), ensure_asciiFalse, indent2 ) except ValueError: response_body response.text[:5000] allure.attach(response_body, 响应体, allure.attachment_type.TEXT) return response这里没有统一调用raise_for_status()因为 400、401、403 等状态本身也可能是异常场景的预期结果应交给用例断言。另外不建议对下单和支付等非幂等 POST 请求进行无条件自动重试。网络超时并不代表服务端没有处理请求盲目重试可能产生重复订单或重复扣款。确实需要重试时应由服务端提供幂等键并在测试中验证幂等行为。5.2权与 Token 管理Token 管理是接口自动化中最容易引入共享状态的地方。比较稳妥的处理方式如下测试账号和密码通过环境变量或 CI 凭据系统注入不写入 Git 仓库。使用 Session 级 Fixture 登录一次并把 Token 放入当前进程的内存上下文。用户端和管理端分别创建客户端避免管理员 Token 被普通用户用例误用。请求日志和 Allure 附件中的 Token、Cookie、密码必须脱敏。Token 过期、伪造 Token 等异常用例使用独立客户端不修改公共客户端。import pytest pytest.fixture(scopesession) def user_client(config): client ApiClient(config.base_url) response client.request( POST, /api/login, json{username: config.username, password: config.password}, ) body response.json() assert response.status_code 200 assert body[code] 0 token body[data][token] client.session.headers.update({Authorization: fBearer {token}}) return client有些框架会把 Token 写入extract.yaml。这种方式便于观察但容易残留上一次执行的数据也不适合并行运行。如果暂时沿用该方案至少应在测试会话开始时清空动态数据更推荐把静态 YAML 保持为只读动态参数保存在 Fixture 或运行时上下文中。5.3参数化与接口关联YAML 数据读取后可以通过pytest.mark.parametrize生成多条测试import pytest cases load_yaml(testcase/order/create_order.yaml) pytest.mark.parametrize(case, cases, idslambda case: case[case_id]) def test_create_order(case, api_client, runtime_context): resolved_case render_variables(case, runtime_context) response api_client.request(**resolved_case[request]) assert_response(response, resolved_case[validate]) extract_variables(response.json(), resolved_case.get(extract), runtime_context)关联参数通常通过 JSONPath 提取登录后提取user_token创建图书后提取book_id创建订单后提取order_id支付完成后提取payment_id。提取前要先完成接口成功断言提取失败时应立即报告变量名和 JSONPath而不是把空值带到下一个接口导致后续错误难以定位。5.4测试数据准备和清理测试数据如果管理不当会导致用例“单独运行成功整套执行失败”。项目采用以下原则每条独立用例创建自己的前置数据用户名、手机号、ISBN 等唯一字段加入run_id或 UUID使用 Fixture 的yield在用例结束后清理数据优先通过业务接口清理数据库删除只作为测试环境的兜底方式记录本次执行创建的资源编号并按“支付记录 → 订单明细 → 订单 → 图书 → 用户”的逆序清理即使用例失败也要在 Fixture 终结器或流水线的always/post阶段执行清理。from uuid import uuid4 import pytest pytest.fixture def new_user(api_client): suffix uuid4().hex[:8] payload { username: fapi_user_{suffix}, password: TestPassword123!, } response api_client.request(POST, /api/users, jsonpayload) user_id response.json()[data][id] yield {id: user_id, **payload} api_client.request(DELETE, f/api/test-support/users/{user_id})测试环境最好提供受权限保护的测试数据清理接口。如果只能直接操作数据库应限制为测试库、使用最小权限账号并在删除前校验目标记录带有本次运行的唯一标识。5.5断言数据库校验HTTP 200 只能说明请求被服务器接受不能证明业务数据正确。例如支付接口返回成功但可能出现以下问题订单状态仍然是“待支付”支付流水没有落库库存没有扣减或被重复扣减接口返回金额与订单实际金额不一致。因此核心链路采用“接口断言 数据库断言”的双重校验操作接口断言数据库断言用户注册返回用户编号、业务码成功用户表存在且密码未明文保存图书上架返回状态为 ON_SALE图书状态、上架时间正确创建订单返回订单号和待支付状态订单主表、明细表、金额正确支付订单返回支付成功订单状态、支付流水、库存变化一致重复支付返回已支付或幂等结果只有一条有效支付记录库存只扣一次库存校验不应只判断某个固定值而应比较操作前后的变化before_stock db.query_one( SELECT stock FROM book WHERE id %s, (book_id,) )[stock] pay_order(order_id) after_stock db.query_one( SELECT stock FROM book WHERE id %s, (book_id,) )[stock] assert after_stock before_stock - quantitySQL 必须参数化数据库账号应遵循最小权限原则。断言应集中在可观察的业务结果上避免过度依赖无关的内部实现字段否则一次正常的数据库重构就可能让大量测试失效。5.6Allure测试报告与Jenkins持续集成本项目以 Allure 作为主要测试报告python -m pytest --alluredirreport/allure-results --clean-alluredir allure generate report/allure-results -o report/allure-report --cleanjenkins持续集成5.7通过接入飞书CLI测试结果回传到飞书群聊编写飞书 CLI通知脚本上层接收报告路径、环境和报告地址等参数底层通过飞书群机器人 Webhook 发送消息。feishu.py主要负责解析报告、计算统计数据、生成飞书文本或消息卡片、调用群机器人 Webhook并把通知过程写入独立日志。def send_fs_msg(content_str, at_allTrue): 向飞书群机器人推送文本消息。 :param content_str: 消息正文 :param at_all: 是否 所有人 :return: conf OperationConfig() url conf.get_feishu_conf(webhook) secret conf.get_feishu_conf(secret) or keyword (conf.get_feishu_conf(keyword) or ).strip() if not url: logs.warning(conf.ini 里没有配置 [FEISHU] webhook跳过飞书通知) return None timestamp, sign generate_sign(secret) text fat user_idall所有人/at\n{content_str} if at_all else content_str if keyword: text f{keyword}\n{text} data { timestamp: timestamp, sign: sign, msg_type: text, content: {text: text}, } res requests.post(url, jsondata, headers{Content-Type: application/json;charsetutf-8}, timeout10) try: body res.json() except ValueError: logs.error(f飞书通知返回的不是 JSON{res.text[:200]}) return None if body.get(code) 0 or body.get(StatusCode) 0: logs.info(f飞书通知发送成功{body}) else: logs.error(f飞书通知发送失败错误码 {body.get(code) or body.get(StatusCode)}{body}) return body6.总结星阅书城接口自动化项目覆盖了注册、登录、图书管理、下单和支付等核心业务。框架通过 YAML 管理测试数据使用 Pytest 完成参数化与 Fixture 管理Requests 负责请求发送JSONPath 实现接口关联MySQL 验证最终数据一致性再通过 Allure、Jenkins 或 Git完成结果展示和持续执行并使用飞书 CLI 将测试摘要及时回传到项目群聊。
