CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-tavern

Simple testing of RESTful APIs

Overview
Eval results
Files

pytest-integration.mddocs/

Pytest Integration

Deep integration with pytest providing custom hooks, CLI options, automatic test file discovery, and seamless integration with pytest plugins and reporting systems.

Capabilities

Pytest Plugin Hooks

Core pytest plugin hooks that integrate Tavern into the pytest framework, enabling automatic test discovery and execution.

def pytest_addhooks(pluginmanager):
    """
    Register custom Tavern hooks with pytest.
    
    Parameters:
    - pluginmanager: Pytest plugin manager instance
    """

def pytest_addoption(parser):
    """
    Add Tavern-specific command line options to pytest.
    
    Parameters:
    - parser: Pytest argument parser
    """

def pytest_collect_file(parent, path):
    """
    Collect Tavern YAML test files during pytest discovery.
    
    Parameters:
    - parent: Parent pytest node
    - path: File path being considered for collection
    
    Returns:
    TavernFile instance if file matches Tavern pattern, None otherwise
    """

Parser Option Management

Programmatic interface for adding Tavern CLI options to pytest parsers.

def add_parser_options(parser_addoption, with_defaults=True):
    """
    Add Tavern CLI options to a parser programmatically.
    
    Parameters:
    - parser_addoption: Parser add_option function
    - with_defaults: Whether to include default values
    """

Custom Hook Execution

Interface for calling custom Tavern hooks during test execution.

def call_hook(test_block_config, hookname, **kwargs):
    """
    Call a custom Tavern hook during test execution.
    
    Parameters:
    - test_block_config: Test configuration object
    - hookname: Name of hook to call
    - **kwargs: Arguments to pass to hook
    """

Custom Hooks

Beta Hook Specifications

Custom hooks for extending Tavern test execution with user-defined functionality.

def pytest_tavern_beta_before_every_test_run(
    test_dict: dict, 
    variables: dict
) -> None:
    """
    Hook called before each test execution.
    
    Parameters:
    - test_dict: Test definition dictionary
    - variables: Current test variables
    """

def pytest_tavern_beta_after_every_test_run(
    test_dict: dict, 
    variables: dict
) -> None:
    """
    Hook called after each test execution.
    
    Parameters:
    - test_dict: Test definition dictionary  
    - variables: Updated test variables
    """

def pytest_tavern_beta_after_every_response(
    expected: Any, 
    response: Any
) -> None:
    """
    Hook called after each response is received.
    
    Parameters:
    - expected: Expected response specification
    - response: Actual response object
    """

def pytest_tavern_beta_before_every_request(
    request_args: MutableMapping
) -> None:
    """
    Hook called before each request is sent.
    
    Parameters:
    - request_args: Mutable request arguments dictionary
    """

CLI Options

Tavern-Specific Options

Command line options added to pytest for controlling Tavern behavior.

Core Configuration:

  • --tavern-global-cfg: Path to global configuration file
  • --tavern-strict: Response matching strictness level
  • --tavern-file-path-regex: Regex pattern for test files (default: r".+\.tavern\.ya?ml$")

Backend Selection:

  • --tavern-http-backend: HTTP backend plugin name (default: "requests")
  • --tavern-mqtt-backend: MQTT backend plugin name (default: "paho-mqtt")
  • --tavern-grpc-backend: gRPC backend plugin name (default: "grpc")

Debugging Options:

  • --tavern-use-default-traceback: Use Python-style tracebacks
  • --tavern-setup-init-logging: Setup simple logger for initialization

HTTP-Specific:

  • --tavern-always-follow-redirects: Always follow HTTP redirects

Usage Examples

Basic Pytest Integration

# Run Tavern tests with pytest
pytest tests/ -v

# Run specific Tavern test file
pytest test_api.tavern.yaml -v

# Run with Tavern-specific options
pytest tests/ --tavern-global-cfg config.yaml --tavern-strict

Custom Hook Implementation

# conftest.py
def pytest_tavern_beta_before_every_test_run(test_dict, variables):
    """Add custom setup before each test."""
    print(f"Running test: {test_dict.get('test_name', 'Unknown')}")
    
    # Add dynamic variables
    variables['timestamp'] = str(int(time.time()))
    variables['test_id'] = str(uuid.uuid4())

def pytest_tavern_beta_after_every_response(expected, response):
    """Log response details."""
    if hasattr(response, 'status_code'):
        print(f"Response status: {response.status_code}")
    
def pytest_tavern_beta_before_every_request(request_args):
    """Modify requests before sending."""
    # Add common headers
    if 'headers' not in request_args:
        request_args['headers'] = {}
    request_args['headers']['X-Test-Run'] = 'true'

Programmatic Parser Configuration

import argparse
from tavern._core.pytest import add_parser_options

# Create custom parser with Tavern options
parser = argparse.ArgumentParser()
add_parser_options(parser.add_argument, with_defaults=True)

# Parse arguments
args = parser.parse_args([
    '--tavern-global-cfg', 'config.yaml',
    '--tavern-strict',
    '--tavern-http-backend', 'custom_requests'
])

File Discovery and Collection

# Custom pytest plugin using Tavern collection
class CustomTavernPlugin:
    def pytest_collect_file(self, parent, path):
        """Collect custom Tavern files."""
        if path.ext == ".yaml" and "api_test" in path.basename:
            # Use Tavern's collection logic
            from tavern._core.pytest import pytest_collect_file
            return pytest_collect_file(parent, path)

Configuration Integration

# pytest.ini
[tool:pytest]
addopts = 
    --tavern-global-cfg=tests/global_config.yaml
    --tavern-strict
    --tavern-http-backend=requests
    -v

testpaths = tests/
python_files = *.tavern.yaml

Advanced Hook Usage

# Plugin with comprehensive hook usage
class TavernTestPlugin:
    def __init__(self):
        self.test_results = []
        self.start_time = None
    
    def pytest_tavern_beta_before_every_test_run(self, test_dict, variables):
        self.start_time = time.time()
        
        # Set up test-specific configuration
        test_name = test_dict.get('test_name', 'unknown')
        variables['test_start_time'] = self.start_time
        variables['test_environment'] = os.getenv('TEST_ENV', 'local')
        
        print(f"Starting test: {test_name}")
    
    def pytest_tavern_beta_after_every_test_run(self, test_dict, variables):
        duration = time.time() - self.start_time
        test_name = test_dict.get('test_name', 'unknown')
        
        self.test_results.append({
            'name': test_name,
            'duration': duration,
            'variables_used': list(variables.keys())
        })
        
        print(f"Completed test: {test_name} in {duration:.2f}s")
    
    def pytest_tavern_beta_before_every_request(self, request_args):
        # Add request tracing
        if 'headers' not in request_args:
            request_args['headers'] = {}
        request_args['headers']['X-Trace-ID'] = str(uuid.uuid4())
        
        # Log outgoing requests
        method = request_args.get('method', 'GET')
        url = request_args.get('url', 'unknown')
        print(f"Sending {method} request to {url}")
    
    def pytest_tavern_beta_after_every_response(self, expected, response):
        # Validate response timing
        if hasattr(response, 'elapsed'):
            if response.elapsed.total_seconds() > 5.0:
                print(f"WARNING: Slow response ({response.elapsed.total_seconds():.2f}s)")
        
        # Log response status
        if hasattr(response, 'status_code'):
            print(f"Received response: {response.status_code}")

Integration with Pytest Ecosystem

Pytest Plugin Compatibility

# Works with pytest-xdist for parallel execution
pytest tests/ -n auto --tavern-global-cfg config.yaml

# Works with pytest-cov for coverage
pytest tests/ --cov=myapp --tavern-strict

# Works with pytest-html for HTML reports
pytest tests/ --html=report.html --self-contained-html

Custom Test Item Classes

# Internal classes used by pytest integration
class TavernFile:
    """Represents a Tavern YAML test file in pytest collection."""
    
class TavernItem:
    """Represents an individual Tavern test case in pytest."""

Types

from typing import Any, MutableMapping
from _pytest.config import Config
from _pytest.nodes import File, Item

TestConfig = "tavern._core.pytest.config.TestConfig"

Install with Tessl CLI

npx tessl i tessl/pypi-tavern

docs

core-execution.md

exceptions.md

index.md

plugin-system.md

pytest-integration.md

response-validation.md

tile.json