Library for accessing Swagger-enabled APIs
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Mock objects and integration testing base classes for testing applications that use bravado. These utilities provide comprehensive testing support including response mocks, fallback result testing, and integration test fixtures for both synchronous and asynchronous HTTP clients.
Mock objects that simulate bravado response behavior for unit testing.
Mock implementation of IncomingResponse for creating test responses.
class IncomingResponseMock(IncomingResponse):
def __init__(self, status_code: int, **kwargs): ...Parameters:
status_code (int): HTTP status code for the mock response**kwargs: Additional response attributes (text, headers, etc.)Usage Example:
from bravado.testing.response_mocks import IncomingResponseMock
# Create mock response
mock_response = IncomingResponseMock(
status_code=200,
text='{"name": "Fluffy", "status": "available"}',
headers={'Content-Type': 'application/json'}
)
print(mock_response.status_code) # 200
print(mock_response.text) # {"name": "Fluffy", "status": "available"}Mock that behaves like both HttpFuture.response() method and BravadoResponse object.
class BravadoResponseMock:
def __init__(self, result, metadata=None): ...
def __call__(self, timeout: float = None, fallback_result=None, exceptions_to_catch: tuple = None) -> 'BravadoResponseMock': ...
@property
def result(self): ...
@property
def metadata(self) -> BravadoResponseMetadata: ...Parameters:
result: The mock result data to returnmetadata: BravadoResponseMetadata instance (optional)timeout (float): Timeout parameter (ignored in mock)fallback_result: Fallback result (ignored unless forced)exceptions_to_catch (tuple): Exception types (ignored in mock)Usage Example:
from bravado.testing.response_mocks import BravadoResponseMock
# Create mock response
mock_result = {'name': 'Fluffy', 'status': 'available'}
mock_response = BravadoResponseMock(mock_result)
# Use as HttpFuture.response() replacement
response = mock_response() # Call like future.response()
pet_data = response.result # Access result like normal BravadoResponse
# Or use directly as BravadoResponse
pet_data = mock_response.resultMock that always triggers fallback result behavior, useful for testing error handling and resilience.
class FallbackResultBravadoResponseMock:
def __init__(self, exception=BravadoTimeoutError(), metadata=None): ...
def __call__(self, timeout: float = None, fallback_result=None, exceptions_to_catch: tuple = None) -> 'FallbackResultBravadoResponseMock': ...
@property
def result(self): ...
@property
def metadata(self) -> BravadoResponseMetadata: ...Parameters:
exception: Exception to simulate (defaults to BravadoTimeoutError)metadata: BravadoResponseMetadata instance (optional)Usage Example:
from bravado.testing.response_mocks import FallbackResultBravadoResponseMock
from bravado.exception import BravadoTimeoutError
# Mock that simulates timeout and uses fallback
fallback_mock = FallbackResultBravadoResponseMock(
exception=BravadoTimeoutError("Request timeout")
)
# Test fallback behavior
fallback_data = {'name': 'Unknown', 'status': 'unavailable'}
response = fallback_mock(fallback_result=fallback_data)
assert response.result == fallback_data
assert response.metadata.is_fallback_result is TrueComprehensive integration testing framework for testing bravado clients with real HTTP servers.
Pytest fixtures for setting up HTTP servers and clients for integration testing.
class IntegrationTestingServicesAndClient:
@pytest.fixture(scope='session')
def swagger_http_server(self): ...
@pytest.fixture(scope='session')
def not_answering_http_server(self): ...
@pytest.fixture(params=['result', 'response'])
def result_getter(self, request): ...Fixtures:
swagger_http_server: Session-scoped HTTP server serving test APIsnot_answering_http_server: Server that doesn't respond (for timeout testing)result_getter: Parameterized fixture for testing both .result() and .response() methodsMixin class providing common fixtures and utilities for integration tests.
class IntegrationTestingFixturesMixin:
http_client: HttpClient
http_client_type: Type[HttpClient]
http_future_adapter_type: Type[FutureAdapter]
connection_errors_exceptions: Set[Exception]
@classmethod
def setup_class(cls): ...
@pytest.fixture
def swagger_client(self) -> SwaggerClient: ...
def encode_expected_response(self, expected_response: dict) -> bytes: ...Class Attributes:
http_client: HTTP client instance for testinghttp_client_type: Type of HTTP client being testedhttp_future_adapter_type: Type of future adapter being testedconnection_errors_exceptions: Set of connection error exception typesMethods:
setup_class(): Class-level setup for test configurationswagger_client(): Fixture that creates SwaggerClient instancesencode_expected_response(): Encode expected response dataBase class with comprehensive integration tests that can be inherited by HTTP client implementations.
class IntegrationTestsBaseClass(IntegrationTestingFixturesMixin):
# Multiple test methods for various scenarios:
# - Basic API operations
# - Error handling (4xx, 5xx status codes)
# - Timeout behavior
# - Connection error handling
# - Authentication testing
# - Request/response validation
# - Fallback result behaviorThis class provides a complete test suite that verifies HTTP client behavior across various scenarios.
import pytest
from unittest.mock import patch
from bravado.testing.response_mocks import BravadoResponseMock
class TestPetService:
def setup_method(self):
self.pet_service = PetService() # Your service that uses bravado
@patch('your_module.swagger_client.pet.getPetById')
def test_get_pet_success(self, mock_get_pet):
# Setup mock response
expected_pet = {'id': 1, 'name': 'Fluffy', 'status': 'available'}
mock_response = BravadoResponseMock(expected_pet)
mock_get_pet.return_value = mock_response
# Test your service
pet = self.pet_service.get_pet(1)
# Assertions
assert pet['name'] == 'Fluffy'
mock_get_pet.assert_called_once_with(petId=1)
@patch('your_module.swagger_client.pet.getPetById')
def test_get_pet_with_fallback(self, mock_get_pet):
# Setup fallback mock
from bravado.testing.response_mocks import FallbackResultBravadoResponseMock
fallback_mock = FallbackResultBravadoResponseMock()
mock_get_pet.return_value = fallback_mock
# Test fallback behavior
pet = self.pet_service.get_pet_with_fallback(1)
assert pet['name'] == 'Unknown' # Your fallback data
assert pet['status'] == 'unavailable'import pytest
from bravado.testing.integration_test import IntegrationTestsBaseClass
from bravado.requests_client import RequestsClient, RequestsFutureAdapter
class TestRequestsClientIntegration(IntegrationTestsBaseClass):
"""Integration tests for RequestsClient."""
@classmethod
def setup_class(cls):
cls.http_client_type = RequestsClient
cls.http_future_adapter_type = RequestsFutureAdapter
cls.connection_errors_exceptions = {ConnectionError}
super().setup_class()
def test_custom_behavior(self, swagger_client):
"""Test specific to RequestsClient behavior."""
response = swagger_client.pet.getPetById(petId=1).response()
assert response.result['name'] == 'doggie'
assert response.metadata.status_code == 200import pytest
from bravado.testing.integration_test import IntegrationTestsBaseClass
from bravado.fido_client import FidoClient, FidoFutureAdapter
import twisted.internet.error
class TestFidoClientIntegration(IntegrationTestsBaseClass):
"""Integration tests for FidoClient."""
@classmethod
def setup_class(cls):
cls.http_client_type = FidoClient
cls.http_future_adapter_type = FidoFutureAdapter
cls.connection_errors_exceptions = {
twisted.internet.error.ConnectionRefusedError,
twisted.internet.error.DNSLookupError
}
super().setup_class()
def test_async_behavior(self, swagger_client):
"""Test async-specific behavior."""
future = swagger_client.pet.getPetById(petId=1)
response = future.response() # This integrates with Twisted
assert response.result['name'] == 'doggie'import bottle
import threading
import time
from bravado.testing.integration_test import _class_fqn
def create_test_server():
"""Create custom test server for your API."""
app = bottle.Bottle()
@app.route('/pets/<pet_id:int>', method='GET')
def get_pet(pet_id):
if pet_id == 404:
bottle.abort(404, "Pet not found")
return {
'id': pet_id,
'name': f'Pet {pet_id}',
'status': 'available'
}
@app.route('/pets', method='POST')
def create_pet():
pet_data = bottle.request.json
pet_data['id'] = 123 # Simulate ID assignment
return pet_data
return app
class TestWithCustomServer:
@pytest.fixture(scope='class')
def test_server(self):
"""Custom test server fixture."""
app = create_test_server()
# Start server in thread
server_thread = threading.Thread(
target=lambda: app.run(host='localhost', port=5000, quiet=True)
)
server_thread.daemon = True
server_thread.start()
time.sleep(0.1) # Wait for server to start
yield 'http://localhost:5000'
def test_custom_api(self, test_server):
from bravado.client import SwaggerClient
# You would need to provide your own swagger spec for the custom server
# This is just an example structure
spec_dict = {
'swagger': '2.0',
'info': {'title': 'Test API', 'version': '1.0'},
'host': 'localhost:5000',
'paths': {
'/pets/{petId}': {
'get': {
'operationId': 'getPetById',
'parameters': [
{'name': 'petId', 'in': 'path', 'type': 'integer', 'required': True}
],
'responses': {'200': {'description': 'Success'}}
}
}
}
}
client = SwaggerClient.from_spec(spec_dict, origin_url=test_server)
response = client.pet.getPetById(petId=1).response()
assert response.result['name'] == 'Pet 1'import pytest
from bravado.testing.response_mocks import FallbackResultBravadoResponseMock
from bravado.exception import HTTPNotFound, BravadoTimeoutError
class TestErrorHandling:
def test_http_404_handling(self):
"""Test handling of HTTP 404 errors."""
# Mock 404 response
from bravado.testing.response_mocks import IncomingResponseMock
mock_response = IncomingResponseMock(
status_code=404,
text='{"error": "Pet not found"}',
headers={'Content-Type': 'application/json'}
)
# Your error handling logic would go here
assert mock_response.status_code == 404
def test_timeout_with_fallback(self):
"""Test timeout handling with fallback results."""
fallback_mock = FallbackResultBravadoResponseMock(
exception=BravadoTimeoutError("Connection timeout")
)
fallback_data = {'error': 'Service temporarily unavailable'}
response = fallback_mock(fallback_result=fallback_data)
assert response.result == fallback_data
assert response.metadata.is_fallback_result is TrueThe testing module provides predefined test data for integration tests:
ROUTE_1_RESPONSE: dict # Sample API response data
ROUTE_2_RESPONSE: dict # Alternative response data
API_RESPONSE: dict # Complete API response structure
SWAGGER_SPEC_DICT: dict # Sample Swagger specificationThese constants provide consistent test data across different test scenarios.
.result() and .response() methods# Good testing example
import pytest
from unittest.mock import patch, MagicMock
from bravado.testing.response_mocks import BravadoResponseMock, FallbackResultBravadoResponseMock
class TestPetService:
@pytest.fixture
def pet_service(self):
return PetService() # Your service class
@pytest.fixture
def mock_client(self):
"""Mock SwaggerClient for testing."""
client = MagicMock()
return client
def test_get_pet_success(self, pet_service, mock_client):
"""Test successful pet retrieval."""
# Setup
expected_pet = {'id': 1, 'name': 'Fluffy', 'status': 'available'}
mock_response = BravadoResponseMock(expected_pet)
mock_client.pet.getPetById.return_value = mock_response
pet_service.client = mock_client
# Execute
result = pet_service.get_pet(1)
# Verify
assert result['name'] == 'Fluffy'
mock_client.pet.getPetById.assert_called_once_with(petId=1)
def test_get_pet_with_timeout_fallback(self, pet_service, mock_client):
"""Test fallback behavior on timeout."""
# Setup fallback mock
fallback_mock = FallbackResultBravadoResponseMock()
mock_client.pet.getPetById.return_value = fallback_mock
pet_service.client = mock_client
# Execute with fallback
result = pet_service.get_pet_with_fallback(1)
# Verify fallback was used
assert result['name'] == 'Unknown Pet'
assert result['status'] == 'unavailable'
@pytest.mark.parametrize("status_code,expected_error", [
(404, HTTPNotFound),
(401, HTTPUnauthorized),
(500, HTTPInternalServerError)
])
def test_get_pet_http_errors(self, pet_service, mock_client, status_code, expected_error):
"""Test various HTTP error scenarios."""
# Setup error mock
mock_client.pet.getPetById.side_effect = expected_error(
response=MagicMock(status_code=status_code)
)
pet_service.client = mock_client
# Execute and verify error
with pytest.raises(expected_error):
pet_service.get_pet(1)Install with Tessl CLI
npx tessl i tessl/pypi-bravado