Backend Development 9 min read

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.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Python Decorator Examples 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)
performancePythonconcurrencyloggingretryerror handlingdecoratorAPI Testing
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.