Simplify API Testing with a Python @extract_value Decorator
Learn how to create and use a Python @extract_value decorator that automatically pulls specific fields from API responses, stores them in a global context, and lets subsequent test steps access these values without manual extraction, complete with step-by-step code examples and common pitfalls.
When testing APIs, developers often need to extract values such as tokens from JSON responses and reuse them across multiple calls. Manually accessing nested fields (e.g., response.json()['data']['token']) is error‑prone and repetitive.
Traditional approach vs. decorator
Without a helper, each request requires explicit extraction and variable assignment, leading to duplicated code and a higher chance of typos. The @extract_value decorator abstracts this pattern: it runs the original function, extracts a value based on a dotted key path, stores the result in a shared dictionary, and optionally injects a global variable for convenient use.
Step‑by‑step implementation
Create a global storage dictionary TEST_DATA = {} Write the decorator
from functools import wraps
def extract_value(key: str, context_var: str):
"""Extract a value from a JSON response and store it.
- key: dotted path like "data.access_token"
- context_var: name to store in TEST_DATA (and optionally as a global)"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
response = func(*args, **kwargs)
json_data = response.json()
value = json_data
for part in key.split('.'):
value = value[part]
# store in shared dict and as a global variable
TEST_DATA[context_var] = value
globals()[context_var] = value
print(f"✅ Extracted {key} → {context_var} = {value}")
return response
return wrapper
return decoratorApply the decorator to API calls
@extract_value(key="data.access_token", context_var="my_token")
def login():
return requests.post("https://api.example.com/login", json={"user": "alice", "pwd": "123"})
def get_user():
headers = {"Authorization": f"Bearer {my_token}"}
return requests.get("https://api.example.com/user", headers=headers)
login()
get_user()Full runnable example
The article provides a self‑contained script that uses httpbin.org to simulate a login and subsequent request. Running the script prints the extracted username and demonstrates that the variable can be used directly in later functions.
import requests
from functools import wraps
# ----- 1. Decorator definition (same as above) -----
def extract_value(key: str, context_var: str):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
response = func(*args, **kwargs)
json_data = response.json()
value = json_data
for part in key.split('.'):
value = value[part]
globals()[context_var] = value
print(f"✅ 提取成功:{key} → {context_var} = {value}")
return response
return wrapper
return decorator
# ----- 2. Test cases -----
@extract_value(key='json.username', context_var='current_user')
def fake_login():
"""Simulate login via httpbin"""
return requests.post('https://httpbin.org/post', json={'username': '小明', 'password': '123456'})
def get_profile():
print(f"正在查询用户:{current_user} 的资料...")
if __name__ == '__main__':
print('🚀 开始测试流程...')
fake_login()
get_profile()
print('🎉 测试完成!')Common questions & tips
Missing field : A KeyError is raised; wrap extraction in try/except or use .get() for safety.
Extracting multiple values : Apply multiple decorators, one per field, remembering that decorators execute from bottom to top.
Variable name collisions : Choose distinct context_var names (e.g., login_token, order_id) to avoid overwriting.
Conclusion
The @extract_value decorator turns repetitive JSON extraction into a single, reusable step, reduces boilerplate, and makes automated API tests cleaner and less error‑prone. By injecting the extracted value as a global variable, subsequent test functions can reference it directly without additional parsing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
