在 YAML 用例中,可以使用占位符来关联嵌套参数。这种方式可以让你在一个地方定义某个参数,然后在其他地方引用它。这在处理复杂的嵌套结构时尤其有用。
以下是如何在 YAML 文件中实现嵌套参数的关联的示例。
1. 更新 YAML 文件
这里我们将定义一个用户的详细信息,并在多个地方引用这些参数。
test_cases.yml
# test_cases.yml
user_details:
name: "John Doe"
email: "john.doe@example.com"
details:
age: 30
address:
city: "New York"
zip: "10001"
contacts:
- type: "phone"
number: "123-456-7890"
- type: "email"
number: "john.doe@example.com"
tests:
- name: "Create User"
method: "POST"
endpoint: "/api/users"
payload:
name: ${user_details.name}
email: ${user_details.email}
details:
age: ${user_details.details.age}
address:
city: ${user_details.details.address.city}
zip: ${user_details.details.address.zip}
contacts: ${user_details.details.contacts}
expected_status: 201
id: "user_id"
- name: "Get User"
method: "GET"
endpoint: "/api/users/{user_id}"
expected_status: 200
depends_on: "Create User"
validate:
field: "details.age"
condition: "greater_than"
value: 18
- name: "Get User City"
method: "GET"
endpoint: "/api/users/{user_id}"
expected_status: 200
depends_on: "Get User"
validate:
field: "details.address.city"
condition: "equals"
value: "New York"
- name: "Get User Phone"
method: "GET"
endpoint: "/api/users/{user_id}"
expected_status: 200
depends_on: "Get User"
validate:
field: "details.contacts.0.number"
condition: "equals"
value: "123-456-7890"
2. 处理占位符的代码
你需要在加载 YAML 文件时处理这些占位符。可以使用简单的文本替换来实现。
import yaml
import requests
import pytest
import re
def load_test_cases(file_path):
"""从 YAML 文件加载测试用例。"""
with open(file_path, 'r') as file:
data = yaml.safe_load(file)
return data
def resolve_placeholders(data, context):
"""解析 YAML 数据中的占位符。"""
if isinstance(data, dict):
return {key: resolve_placeholders(value, context) for key, value in data.items()}
elif isinstance(data, list):
return [resolve_placeholders(item, context) for item in data]
elif isinstance(data, str) and data.startswith("${") and data.endswith("}"):
placeholder = data[2:-1] # 去掉 ${ 和 }
return context.get(placeholder, data) # 返回上下文中的值或原字符串
return data
@pytest.fixture(scope="session")
def base_url():
return "http://localhost:5000" # 替换为你的 API 基础 URL
def run_test_case(base_url, test_case, previous_results):
"""执行单个测试用例并验证响应。"""
url = f"{base_url}{test_case['endpoint']}"
method = test_case['method']
expected_status = test_case['expected_status']
# 替换 URL 中的 {user_id}
for key in previous_results:
if f'{{{key}}}' in url:
url = url.replace(f'{{{key}}}', str(previous_results[key]))
# 发送请求
response = requests.request(method, url, json=test_case.get('payload', {}))
# 断言状态码
assert response.status_code == expected_status
# 记录结果
if 'id' in test_case:
previous_results[test_case['id']] = response.json().get('id') # 记录创建结果的 ID
# 验证返回字段
if 'validate' in test_case:
validate_response(response.json(), test_case['validate'])
def validate_response(response_data, validation):
"""验证响应数据中的字段值是否满足特定条件。"""
field_path = validation['field'].split('.')
actual_value = response_data
for field in field_path:
if isinstance(actual_value, dict) and field in actual_value:
actual_value = actual_value[field]
elif isinstance(actual_value, list) and field.isdigit():
actual_value = actual_value[int(field)]
else:
pytest.fail(f"Field '{validation['field']}' not found in response: {response_data}")
# 执行条件验证
condition = validation['condition']
value = validation['value']
if condition == "equals":
assert actual_value == value, f"Expected {validation['field']} to be '{value}', but got '{actual_value}'"
elif condition == "contains":
assert value in actual_value, f"Expected {validation['field']} to contain '{value}', but got '{actual_value}'"
elif condition == "greater_than":
assert actual_value > value, f"Expected {validation['field']} to be greater than '{value}', but got '{actual_value}'"
elif condition == "less_than":
assert actual_value < value, f"Expected {validation['field']} to be less than '{value}', but got '{actual_value}'"
def test_api():
"""主测试函数,执行所有测试用例。"""
data = load_test_cases('test_cases.yml')
context = data['user_details'] # 获取用户详情作为上下文
test_cases = data['tests']
# 解析占位符
for test_case in test_cases:
if 'payload' in test_case:
test_case['payload'] = resolve_placeholders(test_case['payload'], context)
previous_results = {}
skip_tests = set() # 存储需要跳过的测试用例名称
for test_case in test_cases:
if 'depends_on' in test_case and test_case['depends_on'] in skip_tests:
pytest.skip(f"Skipping '{test_case['name']}' due to failure in '{test_case['depends_on']}'.")
try:
run_test_case(base_url(), test_case, previous_results)
except AssertionError as e:
print(f"Test case '{test_case['name']}' failed: {str(e)}")
skip_tests.add(test_case['name']) # 将当前测试标记为跳过
代码解释
-
YAML 文件:
- 使用
${}
语法来定义占位符,引用user_details
中的参数。
- 使用
-
解析占位符:
- 使用
resolve_placeholders
函数递归地解析 YAML 数据中的占位符,查找上下文中的值替换占位符。
- 使用
-
上下文管理:
- 在
test_api
函数中,将user_details
加载到上下文中,并在解析测试用例的payload
时引用这些值。
- 在
3. 运行测试
确保你已经安装了 pytest
和 requests
库。可以使用以下命令运行测试:
pytest your_test_script.py
总结
通过这种方式,你可以在 YAML 测试用例中灵活地引用嵌套参数,这样可以提高测试用例的可读性和可维护性。使用占位符可以避免重复定义相同的参数,简化测试用例的管理。
标签:case,field,value,用例,pytest,details,test,data,yml From: https://blog.csdn.net/weixin_44872675/article/details/144859054