Python Decorator Examples for API Testing
This article presents ten practical Python decorator patterns—such as logging, performance measurement, exception handling, retry, status‑code validation, parameter checking, rate limiting, data‑driven testing, environment configuration, and concurrent execution—each illustrated with clear use‑case descriptions and complete code snippets for API testing.
Example 1: Logging Decorator
Use case: Record each test function call during API testing.
import logging
def log_function_call(func):
def wrapper(*args, **kwargs):
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info(f"Calling function {func.__name__} with args: {args}, kwargs: {kwargs}")
result = func(*args, **kwargs)
logger.info(f"Function {func.__name__} returned: {result}")
return result
return wrapper
@log_function_call
def test_api_endpoint(url):
# 这里可以是调用API的逻辑
print(f"Testing endpoint at {url}")
test_api_endpoint("https://example.com/api")Example 2: Performance Measurement Decorator
Use case: Measure execution time of API test functions.
import time
def measure_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Function {func.__name__} took {end_time - start_time:.4f} seconds to run.")
return result
return wrapper
@measure_time
def test_api_performance(url):
# 这里可以是调用API的逻辑
print(f"Testing performance of endpoint at {url}")
test_api_performance("https://example.com/api")Example 3: Exception Handling Decorator
Use case: Capture and handle exceptions that occur during API testing.
import requests
def handle_exceptions(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"An error occurred in {func.__name__}: {e}")
return None
return wrapper
@handle_exceptions
def test_api_with_exceptions(url):
response = requests.get(url)
if response.status_code == 200:
print("Request successful")
else:
raise Exception(f"Request failed with status code {response.status_code}")
test_api_with_exceptions("https://example.com/api")Example 4: Retry Mechanism Decorator
Use case: Automatically retry a failed API test a configurable number of times.
import requests
def retry(max_retries=3):
def decorator(func):
def wrapper(*args, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt < max_retries - 1:
print(f"Attempt {attempt + 1} failed, retrying...")
else:
print(f"Max retries ({max_retries}) reached, last error: {e}")
return None
return wrapper
return decorator
@retry(max_retries=3)
def test_api_with_retry(url):
response = requests.get(url)
if response.status_code == 200:
print("Request successful")
else:
raise Exception(f"Request failed with status code {response.status_code}")
test_api_with_retry("https://example.com/api")Example 5: Response Status‑Code Validation Decorator
Use case: Ensure the API returns the expected HTTP status code.
import requests
def validate_status_code(expected_status=200):
def decorator(func):
def wrapper(*args, **kwargs):
response = func(*args, **kwargs)
if response.status_code == expected_status:
print(f"Status code is as expected: {response.status_code}")
else:
raise Exception(f"Unexpected status code: {response.status_code}")
return response
return wrapper
return decorator
@validate_status_code(expected_status=200)
def test_api_status(url):
return requests.get(url)
test_api_status("https://example.com/api")Example 6: Parameter Validation Decorator
Use case: Verify that required parameters are present and of correct types before invoking the API test.
def validate_params(*param_names, **param_types):
def decorator(func):
def wrapper(*args, **kwargs):
for name in param_names:
if name not in kwargs:
raise ValueError(f"Missing required parameter: {name}")
for name, type_ in param_types.items():
if name in kwargs and not isinstance(kwargs[name], type_):
raise TypeError(f"Parameter {name} must be of type {type_.__name__}")
return func(*args, **kwargs)
return wrapper
return decorator
@validate_params("url", url=str)
def test_api_with_params(url):
print(f"Testing endpoint at {url}")
test_api_with_params(url="https://example.com/api")Example 7: Call‑Rate Limiting Decorator
Use case: Limit how frequently API test functions can be invoked to avoid overloading the server.
import time
def limit_calls(max_calls_per_minute=60):
def decorator(func):
call_times = []
def wrapper(*args, **kwargs):
current_time = time.time()
while call_times and current_time - call_times[0] > 60:
call_times.pop(0)
if len(call_times) >= max_calls_per_minute:
raise Exception("Maximum calls per minute exceeded")
call_times.append(current_time)
return func(*args, **kwargs)
return wrapper
return decorator
@limit_calls(max_calls_per_minute=60)
def test_api_limit_calls(url):
print(f"Testing endpoint at {url}")
for _ in range(61):
test_api_limit_calls(url="https://example.com/api")
time.sleep(1)Example 8: Data‑Driven Test Decorator
Use case: Run the same API test multiple times with different input data sets.
def data_driven_test(test_data):
def decorator(func):
def wrapper():
for data in test_data:
func(**data)
return wrapper
return decorator
@test_data([
{"url": "https://example.com/api1"},
{"url": "https://example.com/api2"}
])
def test_api_multiple_urls(url):
print(f"Testing endpoint at {url}")
test_api_multiple_urls()Example 9: Environment Configuration Decorator
Use case: Switch API endpoints based on the selected environment (development, testing, production).
def configure_environment(environment="dev"):
environments = {
"dev": "https://dev.example.com",
"test": "https://test.example.com",
"prod": "https://api.example.com"
}
def decorator(func):
def wrapper(*args, **kwargs):
base_url = environments.get(environment, "https://default.example.com")
kwargs["base_url"] = base_url
return func(*args, **kwargs)
return wrapper
return decorator
@configure_environment(environment="test")
def test_api_with_environment(base_url, endpoint):
print(f"Testing endpoint at {base_url}/{endpoint}")
test_api_with_environment(endpoint="api")Example 10: Concurrent Execution Decorator
Use case: Execute API tests concurrently to improve testing throughput.
import concurrent.futures
def concurrent_execute(max_workers=5):
def decorator(func):
def wrapper(*args, **kwargs):
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = [executor.submit(func, *arg, **kwarg) for arg, kwarg in zip(args, kwargs)]
concurrent.futures.wait(futures)
return wrapper
return decorator
@concurrent_execute(max_workers=5)
def test_api_concurrently(url):
print(f"Testing endpoint at {url}")
urls = ["https://example.com/api1", "https://example.com/api2", "https://example.com/api3"]
test_api_concurrently(urls)Test Development Learning Exchange
Test Development Learning Exchange
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.