
Pytest 默认对相同参数值的 fixture 进行缓存,导致 @pytest.mark.parametrize 中重复参数仅触发一次 fixture 执行;本文通过将 fixture 改为返回可调用函数的方式,实现在单个测试内多次、独立地调用 DynamoDB 数据插入逻辑。
pytest 默认对相同参数值的 fixture 进行缓存,导致 @pytest.mark.parametrize 中重复参数仅触发一次 fixture 执行;本文通过将 fixture 改为返回可调用函数的方式,实现在单个测试内多次、独立地调用 dynamodb 数据插入逻辑。
在 Pytest 中,fixture 的执行行为由其 scope 和参数化机制共同决定。当使用 indirect=True 对 fixture 进行参数化时(如 @pytest.mark.parametrize("function_order", [...], indirect=True)),Pytest 会根据参数值的唯一性对 fixture 实例进行去重缓存——即使你传入两个完全相同的字典 {"delivery_date": "12-12-2024"},Pytest 仍将其视为“同一参数”,因此只运行一次 fixture,而非两次。
这与业务测试需求冲突:你的场景需要在同一测试中模拟已存在 2 条同日期订单,从而验证第 3 次提交触发 400 限流响应。此时,必须确保 fixture 被调用两次,且每次生成独立的 order_id 并写入 DynamoDB。
✅ 正确解法:Fixture 返回工厂函数(Factory Pattern)
将 fixture 改造为返回一个闭包函数,把参数传递逻辑从 pytest 参数化转移到测试函数内部调用:
import uuid
import pytest
@pytest.fixture(scope="function")
def function_order(request, dynamodb_client, cleanup_orders):
def _create_order(delivery_date="01-01-2022"):
order_id = f"ORDER-{uuid.uuid4()}"
record = {
"order_id": {"S": order_id},
"delivery_date": {"S": delivery_date},
}
dynamodb_client.put_item(
TableName="orders",
Item=record,
)
cleanup_orders.append(order_id) # 确保清理逻辑仍生效
return {"order_id": order_id, "record": record}
return _create_order
对应测试用例改为显式两次调用:
def test_post_v1_orders_exceeds_order_limit_returns_400(
request_helper, function_order
):
delivery_date = "12-12-2024"
# 显式插入两条同日期订单
function_order(delivery_date)
function_order(delivery_date)
# 触发第 3 次提交,预期失败
response = request_helper.post(
"/v1/orders",
body=order.order_record(delivery_date=delivery_date),
)
assert response.status_code == 400
assert response.json().get("error") == f"Order limit exceeded for date: {delivery_date}. Max orders: 2"
⚠️ 关键注意事项
-
Scope 保持
function:确保每次测试函数执行时cleanup_orders是全新列表,避免跨测试污染; -
cleanup_orders必须是可变对象(如 list),且在 fixture 内部append(),以保证清理逻辑能收集所有生成的order_id; -
避免在 fixture 中直接使用
request.param:原方案依赖 pytest 参数化机制,而该机制天然去重;改用函数调用后,控制权回归测试代码,灵活性与确定性大幅提升; -
UUID 生成需在
_create_order内部:确保每次调用生成全新order_id,防止 DynamoDBPutItem因主键冲突失败(假设order_id是主键); - 若需更复杂状态管理(如验证当前 DB 中已有几条某日期订单),建议额外封装辅助函数或 fixture(如
count_orders_by_date),增强可测性。
此模式不仅解决重复参数问题,还提升了测试意图的可读性与可控性——“我要插入两条数据”比“我期望 fixture 被参数化两次”更直观、更健壮。










