1. 为什么我们需要线性测试脚本?
在接口自动化测试领域,线性测试脚本是最基础也是最实用的测试方法之一。我刚开始做自动化测试时,总想着直接上框架、搞复杂架构,结果发现连最基本的接口调用都写不利索。后来才明白,线性脚本就像学编程时的"Hello World",看似简单却能打下坚实基础。
线性测试脚本的核心特点是按照固定顺序执行测试步骤,每个步骤的输出作为下一个步骤的输入。这种模式特别适合:
- 业务流程明确的场景(如登录→查询→下单)
- 需要维护上下文状态的测试(如token传递)
- 快速验证接口连通性的场景
提示:不要小看线性脚本,很多大厂的自动化测试体系底层都是基于线性脚本组合构建的,只是加上了数据驱动、关键字驱动等上层设计。
2. 环境准备与工具选型
2.1 Python + Requests基础环境
我推荐使用Python 3.x + Requests库的组合,这是目前最轻量也最主流的接口测试方案。相比JMeter等工具,代码化的测试脚本更灵活、更容易版本化管理。
安装只需要两行命令:
pip install requests pip install pytest # 测试框架可选选择Requests库而不是urllib的原因是:
- 更人性化的API设计(session保持、超时控制等)
- 内置JSON解析(response.json()直接转对象)
- 社区活跃,遇到问题容易找到解决方案
2.2 辅助工具配置
建议搭配这些工具提升效率:
- Postman:用于接口调试和文档查看
- Allure:生成美观的测试报告
- Git:版本管理(测试脚本也是代码!)
3. 编写第一个线性测试脚本
3.1 用户登录场景实战
我们以一个典型的登录→获取用户信息流程为例:
import requests # 1. 登录接口 login_url = "https://api.example.com/login" login_data = { "username": "testuser", "password": "123456" } login_res = requests.post(login_url, json=login_data) token = login_res.json()["token"] # 获取返回的token # 2. 带token请求用户信息 user_url = "https://api.example.com/userinfo" headers = {"Authorization": f"Bearer {token}"} user_res = requests.get(user_url, headers=headers) # 3. 断言验证 assert user_res.status_code == 200 assert "testuser" in user_res.json()["username"]这个脚本完整演示了:
- 接口调用顺序依赖(先登录后查询)
- 上下文传递(token从登录响应提取并用于后续请求)
- 结果验证(状态码和内容断言)
3.2 电商下单场景扩展
更复杂的电商下单流程示例:
# 续接前面的登录代码... # 3. 查询商品 product_res = requests.get("https://api.example.com/products/123") product_id = product_res.json()["id"] # 4. 加入购物车 cart_data = { "product_id": product_id, "quantity": 2 } requests.post("https://api.example.com/cart", json=cart_data, headers=headers) # 5. 创建订单 order_res = requests.post("https://api.example.com/orders", headers=headers) order_id = order_res.json()["order_id"] # 6. 支付验证 pay_res = requests.post(f"https://api.example.com/pay/{order_id}", headers=headers) assert pay_res.json()["status"] == "success"4. 脚本优化与健壮性提升
4.1 异常处理机制
原始脚本没有考虑网络异常、接口失败等情况。改进版本:
try: login_res = requests.post(login_url, json=login_data, timeout=5) login_res.raise_for_status() # 自动检查4xx/5xx错误 token = login_res.json().get("token") if not token: raise ValueError("Token not found in response") except requests.exceptions.RequestException as e: print(f"Login failed: {str(e)}") exit(1)关键改进点:
- 添加超时控制(timeout=5)
- 自动检查HTTP错误状态(raise_for_status)
- 验证响应数据完整性(token存在性检查)
4.2 可配置化改造
将硬编码的参数提取为配置文件(config.yaml):
base_url: "https://api.example.com" credentials: username: "testuser" password: "123456"脚本改造后:
import yaml with open("config.yaml") as f: config = yaml.safe_load(f) base_url = config["base_url"] login_url = f"{base_url}/login" login_data = { "username": config["credentials"]["username"], "password": config["credentials"]["password"] }4.3 日志记录增强
添加详细的日志记录:
import logging logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", handlers=[ logging.FileHandler("test.log"), logging.StreamHandler() ] ) logging.info(f"Requesting {login_url} with data: {login_data}") response = requests.post(login_url, json=login_data) logging.info(f"Response status: {response.status_code}, body: {response.text}")5. 常见问题与调试技巧
5.1 接口依赖问题
当A接口依赖B接口的输出时,常见陷阱包括:
- 没有检查前置接口的响应状态
- 错误解析了响应数据结构
- 没有考虑接口幂等性(如重复下单)
调试建议:
- 使用Postman手动验证每个接口
- 打印完整的请求和响应(包括headers)
- 添加中间断言验证关键数据
5.2 环境差异处理
不同环境(测试/预发/生产)的常见差异:
- 域名不同
- 认证方式不同
- 数据隔离策略不同
解决方案:
import os env = os.getenv("ENV", "test") config = { "test": {"base_url": "https://test.api.com"}, "prod": {"base_url": "https://api.com"} }[env]5.3 敏感数据处理
不要在代码中硬编码密码!推荐方案:
- 使用环境变量:
import os password = os.getenv("API_PASSWORD")- 使用密钥管理服务(如AWS Secrets Manager)
- 使用加密的配置文件
6. 从线性脚本到测试框架
当脚本数量增多时,可以考虑逐步演进:
6.1 公共方法封装
将重复代码提取为公共模块(如api_client.py):
class APIClient: def __init__(self, base_url): self.session = requests.Session() self.base_url = base_url def login(self, username, password): url = f"{self.base_url}/login" data = {"username": username, "password": password} res = self.session.post(url, json=data) res.raise_for_status() return res.json()["token"]6.2 测试数据分离
使用CSV或JSON文件管理测试数据:
import csv with open("test_data.csv") as f: reader = csv.DictReader(f) test_cases = list(reader) for case in test_cases: # 使用case["username"]等字段6.3 集成测试报告
使用Allure生成美观报告:
import allure @allure.title("用户登录测试") def test_login(): with allure.step("步骤1:发送登录请求"): res = requests.post(login_url, json=login_data) with allure.step("验证响应"): assert res.status_code == 2007. 真实项目经验分享
在电商项目中,我遇到过这些典型问题:
- Cookie失效问题:解决方案是添加自动重试机制
def request_with_retry(url, max_retries=3): for i in range(max_retries): try: res = requests.get(url) if res.status_code != 401: # 未授权 return res # 重新登录 login() except Exception as e: if i == max_retries - 1: raise- 接口性能验证:虽然线性脚本主要验证功能,但可以简单加入耗时检查
start = time.time() res = requests.get(url) elapsed = time.time() - start assert elapsed < 1.0 # 响应时间应小于1秒- 数据污染问题:测试完成后自动清理测试数据
def teardown(): requests.delete(f"{base_url}/test-data")重要提示:线性脚本虽然简单,但在实际项目中要注意:
- 每个脚本应该有明确的初始状态和清理逻辑
- 关键断言不能只验证HTTP状态码,要检查业务逻辑状态
- 考虑接口的幂等性和并发安全性