Testing code that uses bravado

Writing tests is crucial in making sure your code works and behaves as expected. bravado ships with two classes that will help you create robust unit tests to verify the correctness of your code. We’ll be using the excellent pytest library in this example.

First of all, let’s define the code we’d like to test:

from itertools import chain

from bravado.client import SwaggerClient

def get_available_pet_photos():
    petstore = SwaggerClient.from_url(
        'http://petstore.swagger.io/swagger.json',
    )
    pets = petstore.pet.findPetsByStatus(status=['available']).response(
        timeout=0.5,
        fallback_result=lambda e: [],
    ).result

    return chain.from_iterable(pet.photoUrls for pet in pets)

First of all, in order to make sure your code doesn’t do any network requests, you need to mock out the bravado client:

import mock
import pytest

from bravado.client import SwaggerClient

@pytest.fixture
def mock_client():
    mock_client = mock.Mock(name='mock SwaggerClient')
    with mock.patch.object(SwaggerClient, 'from_url', return_value=mock_client):
        yield mock_client

Now we can mock out that call to findPetsByStatus by using the bravado.testing.response_mocks.BravadoResponseMock class:

import mock

from bravado.testing.response_mocks import BravadoResponseMock

from mypackage import get_available_pet_photos

def test_get_available_pet_photos(mock_client):
    mock_pets = [
        mock.Mock(
            photoUrls=['https://example.com/image.png'],
        ),
        mock.Mock(
            photoUrls=[
                'https://example.com/image2.png',
                'https://example.com/image3.png',
            ],
        ),
    ]

    mock_client.pet.findPetsByStatus.return_value.response = BravadoResponseMock(
        result=mock_pets,
    )

    pet_photos = get_available_pet_photos()

    assert list(pet_photos) == [
        'https://example.com/image.png',
        'https://example.com/image2.png',
        'https://example.com/image3.png',
    ]

Note that it’s your responsibility to ensure that what you set as result for BravadoResponseMock is sufficiently similar to what bravado would return in production. We’ve used a Mock class here; another option is to define namedtuples that correspond to your Swagger spec objects. This gives you even greater confidence in the correctness of your code since access to undefined fields will result in an error.

Testing degraded responses

Use FallbackResultBravadoResponseMock to test fallback results. It works similarly, but you don’t have to pass the result to the constructor, since your fallback result callback will determine the result. Let’s add another test to verify our fallback result code path works properly:

from bravado.testing.response_mocks import FallbackResultBravadoResponseMock

from example import get_available_pet_photos

def test_get_available_pet_photos_fallback_result(mock_client):
    mock_client.pet.findPetsByStatus.return_value\
        .response = FallbackResultBravadoResponseMock()

    pet_photos = get_available_pet_photos()

    assert list(pet_photos) == []

Note that you can pass in a custom exception instance to FallbackResultBravadoResponseMock if you need to trigger specific exception handling in your fallback result callback.

Setting custom response metadata

Both BravadoResponseMock as well as FallbackResultBravadoResponseMock accept an optional metadata argument. Just pass in an instance of BravadoResponseMetadata that you’d like to be used. A default one will be provided otherwise.