CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-vedro

Pragmatic Testing Framework for Python with BDD-style syntax and pluggable architecture

49

1.08x
Quality

Pending

Does it follow best practices?

Impact

49%

1.08x

Average score across 10 eval scenarios

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

parameterization.mddocs/

Test Parameterization

Powerful parameterization system supporting multiple parameter sets with optional decorators for enhanced functionality.

Capabilities

Basic Parameterization

The core params decorator for creating multiple test instances with different input values.

class params:
    """
    Parameterization decorator for creating multiple test instances.
    
    Can be used as a decorator directly or with additional decorators
    via class item access.
    """
    
    def __init__(self, *args, **kwargs):
        """
        Initialize parameterization with positional and keyword arguments.
        
        Args:
            *args: Positional arguments to pass to the test
            **kwargs: Keyword arguments to pass to the test
        """
    
    def __call__(self, fn: F) -> F:
        """
        Apply parameters to the test function or class constructor.
        
        Args:
            fn: Function or class to parameterize
            
        Returns:
            The parameterized function/class
        """
    
    def __class_getitem__(cls, item) -> Callable[..., Parameterized]:
        """
        Create parameterization with additional decorators.
        
        Args:
            item: Single decorator or tuple of decorators
            
        Returns:
            Callable that creates Parameterized instance with decorators
        """

Usage Example - Class-based

from vedro import Scenario, params

class Scenario(vedro.Scenario):
    subject = "mathematical operations"
    
    @params(2, 3, 5)        # a=2, b=3, expected=5
    @params(10, 15, 25)     # a=10, b=15, expected=25
    @params(-5, 8, 3)       # a=-5, b=8, expected=3
    def __init__(self, a, b, expected):
        self.a = a
        self.b = b
        self.expected = expected
    
    def when_numbers_are_added(self):
        self.result = self.a + self.b
        
    def then_result_matches_expected(self):
        assert self.result == self.expected

Usage Example - Function-based

from vedro import scenario, params, given, when, then, ensure

@params("admin", 200)
@params("user", 200)
@params("guest", 403)
@scenario("API access with different user roles")
def test_api_access(role, expected_status):
    
    @given(f"user with {role} role")
    def setup():
        return authenticate_user_with_role(role)
    
    @when("user accesses protected resource")
    def action(user):
        return api_request("/protected-resource", auth=user.token)
    
    @then(f"response has status {expected_status}")
    def verification(response):
        ensure(response.status_code).equals(expected_status)

Parameterization with Keywords

Support for keyword arguments in parameterization for more readable tests.

@params(username="admin", password="admin123", should_succeed=True)
@params(username="user", password="wrongpass", should_succeed=False)
@params(username="", password="", should_succeed=False)
@scenario("Login with various credentials")
def test_login(username, password, should_succeed):
    
    @given("login credentials")
    def setup():
        return {"username": username, "password": password}
    
    @when("user attempts login")
    def action(credentials):
        try:
            result = login(credentials["username"], credentials["password"])
            return {"success": True, "result": result}
        except AuthenticationError as e:
            return {"success": False, "error": str(e)}
    
    @then("login outcome matches expectation")
    def verification(outcome):
        ensure(outcome["success"]).equals(should_succeed)

Parameterization with Decorators

Advanced parameterization that applies additional decorators to specific parameter sets.

from vedro import skip

# Apply skip decorator to specific parameter sets
@params[skip("Flaky test")]("slow_endpoint", 30)
@params("fast_endpoint", 5)
@params("medium_endpoint", 15)
@scenario("API response times")
def test_response_times(endpoint, max_time):
    
    @when(f"requesting {endpoint}")
    def action():
        start_time = time.time()
        response = api_request(f"/api/{endpoint}")
        duration = time.time() - start_time
        return {"response": response, "duration": duration}
    
    @then(f"response time is under {max_time} seconds")
    def verification(result):
        ensure(result["response"].status_code).equals(200)
        ensure(result["duration"]).is_less_than(max_time)

Multiple Decorator Application

Apply multiple decorators to parameterized tests.

from vedro import skip_if, only

# Apply multiple decorators to parameter sets
@params[(skip_if(not EXTERNAL_API_AVAILABLE), only)](
    "external_api", "https://api.external.com"
)
@params("internal_api", "http://localhost:8000")
@scenario("API integration tests")
def test_api_integration(api_name, base_url):
    
    @when(f"calling {api_name}")
    def action():
        return api_request(f"{base_url}/health")
    
    @then("API responds successfully")
    def verification(response):
        ensure(response.status_code).equals(200)

Types

Parameterized

Internal class representing a parameterized test with arguments and decorators.

class Parameterized:
    """
    Represents a parameterized function or method with stored arguments
    and decorators that are applied when the function is invoked.
    """
    
    def __init__(self, args, kwargs, decorators: Tuple): ...
    def __call__(self, fn: F) -> F: ...

Type Annotations

For type checking support, params provides appropriate type annotations.

# Type-checking support
F = TypeVar("F", bound=Callable[..., Any])
ItemType = Union[Callable[[F], F], Tuple[Callable[[F], F], ...]]

Advanced Patterns

Complex Parameter Objects

Use complex objects as parameters for comprehensive test scenarios:

from dataclasses import dataclass

@dataclass
class UserProfile:
    name: str
    email: str
    role: str
    active: bool

@params(UserProfile("John Doe", "john@example.com", "admin", True))
@params(UserProfile("Jane Smith", "jane@example.com", "user", True))
@params(UserProfile("Bob Johnson", "bob@example.com", "guest", False))
@scenario("User profile management")
def test_user_profiles(profile):
    
    @given("user profile data")
    def setup():
        return profile
    
    @when("profile is processed")
    def action(user_profile):
        return process_user_profile(user_profile)
    
    @then("profile is handled correctly")
    def verification(result):
        if profile.active:
            ensure(result.status).equals("processed")
        else:
            ensure(result.status).equals("inactive")

Parameter Generation

Generate parameters dynamically for data-driven tests:

# Generate test parameters from external data
test_cases = [
    params(input_val, expected)
    for input_val, expected in load_test_data("math_operations.json")
]

# Apply generated parameters
for param_decorator in test_cases:
    @param_decorator
    @scenario("Generated math test")
    def test_generated_math(input_val, expected):
        @when("calculation is performed")
        def action():
            return complex_calculation(input_val)
        
        @then("result matches expected value")
        def verification(result):
            ensure(result).equals(expected)

Conditional Parameterization

Skip or modify parameters based on runtime conditions:

import sys

# Conditionally apply parameters based on Python version
version_params = []
if sys.version_info >= (3, 9):
    version_params.append(params("python39_feature", True))
if sys.version_info >= (3, 10):
    version_params.append(params("python310_feature", True))

version_params.append(params("legacy_feature", True))

for param_decorator in version_params:
    @param_decorator
    @scenario("Version-specific features")
    def test_version_features(feature_name, should_work):
        @when(f"using {feature_name}")
        def action():
            return test_feature(feature_name)
            
        @then("feature works as expected")
        def verification(result):
            ensure(result.success).equals(should_work)

docs

artifacts-files.md

assertions.md

cli.md

configuration.md

context-cleanup.md

events.md

execution-control.md

index.md

parameterization.md

test-definition.md

tile.json