Skip to main content

A fixture which allows easy replacement of fastapi dependencies for testing

Project description

pytest-fastapi-deps

Build status Python Version Dependencies Status

Code style: black Security: bandit Pre-commit Semantic Versions License

A fixture which allows easy replacement of fastapi dependencies for testing

Installation

pip install pytest-fastapi-deps

or install with Poetry

poetry add pytest-fastapi-deps

Use case

Suppose that you have this fastapi endpoint which has a couple of dependencies:

from fastapi import Depends, FastAPI

app = FastAPI()


async def first_dep():
    return {"skip": 0, "limit": 100}


def second_dep():
    return {"skip": 20, "limit": 50}


@app.get("/depends/")
async def get_depends(
    first_dep: dict = Depends(first_dep), second_dep: dict = Depends(second_dep)
):
    return {"first_dep": first_dep, "second_dep": second_dep}

For simplicity, this example holds static dictionaries, but in reality these dependencies can be anything: dynamic configuration, database information, the current user's information, etc.

If you want to test your fastapi endpoint you might wish to mock or replace these dependencies with your test code.

This is where the fastapi_dep fixture comes to play.

Usage

The most basic usage is to replace a dependency with a context manager:

from my_project.main import app, first_dep, second_dep
from fastapi.testclient import TestClient

client = TestClient(app)

def my_second_override():
    return {"another": "override"}


def test_get_override_two_dep(fastapi_dep):
    with fastapi_dep(app).override(
        {
            first_dep: "plain_override_object",
            second_dep: my_second_override,
        }
    ):
        response = client.get("/depends")
        assert response.status_code == 200
        assert response.json() == {
            "first_dep": "plain_override_object",
            "second_dep": {"another": "override"},
        }

Note how easy it is: you add the fastapi_dep fixture, initialize it with the fastapi app and send a dictionary of overrides: the keys are the original functions while the values are plain objects that would be returned or replacement functions that would be called.

If your use case is to replace the dependencies for the entire duration of your test, you can use pytest indirect parameters to simplify the body of your test:

import pytest

from my_project.main import app, first_dep, second_dep
from fastapi.testclient import TestClient

client = TestClient(app)

@pytest.mark.parametrize(
    "fastapi_dep",
    [
        (
            app,
            {first_dep: lambda: {"my": "override"}},
        )
    ],
    indirect=True,
)
def test_get_override_indirect_dep_param(fastapi_dep):
    response = client.get("/depends")
    assert response.status_code == 200
    assert response.json() == {
        "first_dep": {"my": "override"},
        "second_dep": {"skip": 20, "limit": 50},
    }

You must use indirect=True and pass a tuple where the first item is the app and the second item is the dictionary with replacement functions.

You can do more fancy stuff and utilize the nature of nested python context managers:

from my_project.main import app, first_dep, second_dep
from fastapi.testclient import TestClient

client = TestClient(app)


def test_get_override_dep_inner_context(fastapi_dep):
    with fastapi_dep(app).override({first_dep: lambda: {"my": "override"}}):
        response = client.get("/depends")
        assert response.status_code == 200
        assert response.json() == {
            "first_dep": {"my": "override"},  # overridden 
            "second_dep": {"skip": 20, "limit": 50},  # stayed the same
        }

        # add another override
        with fastapi_dep(app).override({second_dep: lambda: {"another": "override"}}):
            response = client.get("/depends")
            assert response.status_code == 200
            assert response.json() == {
                "first_dep": {"my": "override"},  # overridden 
                "second_dep": {"another": "override"},  # overridden 
            }

        # second override is gone - expect that only the first is overridden
        response = client.get("/depends")
        assert response.status_code == 200
        assert response.json() == {
            "first_dep": {"my": "override"},  # overridden 
            "second_dep": {"skip": 20, "limit": 50},  # returned to normal behaviour 
        }

    # back to normal behaviour
    response = client.get("/depends")
    assert response.status_code == 200
    assert response.json() == {
        "first_dep": {"skip": 0, "limit": 100},
        "second_dep": {"skip": 20, "limit": 50},
    }

📈 Releases

You can see the list of available releases on the GitHub Releases page.

We follow Semantic Versions specification.

🛡 License

License

This project is licensed under the terms of the MIT license. See LICENSE for more details.

📃 Citation

@misc{pytest-fastapi-deps,
  author = {Peter Kogan},
  title = {A fixture which allows easy replacement of fastapi dependencies for testing},
  year = {2022},
  publisher = {GitHub},
  journal = {GitHub repository},
  howpublished = {\url{https://github.com/pksol/pytest-fastapi-deps}}
}

Credits 🚀 Your next Python package needs a bleeding-edge project structure.

This project was generated with python-package-template

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest-fastapi-deps-0.2.0.tar.gz (6.8 kB view details)

Uploaded Source

Built Distribution

pytest_fastapi_deps-0.2.0-py3-none-any.whl (5.5 kB view details)

Uploaded Python 3

File details

Details for the file pytest-fastapi-deps-0.2.0.tar.gz.

File metadata

  • Download URL: pytest-fastapi-deps-0.2.0.tar.gz
  • Upload date:
  • Size: 6.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.4 CPython/3.8.10 Linux/5.4.0-1078-azure

File hashes

Hashes for pytest-fastapi-deps-0.2.0.tar.gz
Algorithm Hash digest
SHA256 1a009fe08b81f9fe0e9ced7bcdd0d6833a4ef400029ac74b692bbeee4457ac42
MD5 477cea2e7b9b81ac40155bcb94d72e07
BLAKE2b-256 a0b700bcf42959f6b8bf86b9595a16a9201a5c092dc3917508782228fa7a1062

See more details on using hashes here.

File details

Details for the file pytest_fastapi_deps-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pytest_fastapi_deps-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 28ac340e3976c7423ff8fcbf9b682f1aa9c29610f0e43f409fb891cc1c7d38d1
MD5 1728b18f7fc65d5c8098f81b87f5cdd8
BLAKE2b-256 62d175e1cdf297951b639e15e0173cc2c97a677e37d0d00cd8e9e2c318c603ef

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page