2

I have a very simple fastapi application which i want to test , the code for dummy_api.py is as follows :

import os
from fastapi import FastAPI


app = FastAPI()


@app.get(os.getenv("ENDPOINT", "/get"))
def func():
    return {
        "message": "Endpoint working !!!"
    }

When i want to test this i am using the below file :

from fastapi.testclient import TestClient
import dummy_api


def test_dummy_api():
    client = TestClient(dummy_api.app)
    response = client.get("/get")
    assert response.status_code == 200


def test_dummy_api_with_envar(monkeypatch):
    monkeypatch.setenv("ENDPOINT", "dummy")
    client = TestClient(dummy_api.app)
    response = client.get("/dummy")
    assert response.status_code == 200

However i am unable to mock the environment variable part as one of the tests fail with a 404.

pytest -s -v
================================================================= test session starts ==================================================================
platform linux -- Python 3.8.5, pytest-6.2.2, py-1.9.0, pluggy-0.13.1 -- /home/subhayan/anaconda3/envs/fastapi/bin/python
cachedir: .pytest_cache
rootdir: /home/subhayan/Codes/ai4bd/roughdir
collected 2 items                                                                                                                                      

test_dummy_api.py::test_dummy_api PASSED
test_dummy_api.py::test_dummy_api_with_envar FAILED

======================================================================= FAILURES =======================================================================
______________________________________________________________ test_dummy_api_with_envar _______________________________________________________________

monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7ff8c4cf1430>

    def test_dummy_api_with_envar(monkeypatch):
        monkeypatch.setenv("ENDPOINT", "dummy")
        client = TestClient(dummy_api.app)
        response = client.get("/dummy")
>       assert response.status_code == 200
E       assert 404 == 200
E         +404
E         -200

test_dummy_api.py:15: AssertionError
=============================================================== short test summary info ================================================================
FAILED test_dummy_api.py::test_dummy_api_with_envar - assert 404 == 200
============================================================= 1 failed, 1 passed in 0.19s ==============================================================

Can anyone point out where am i going wrong please !!

3 Answers 3

7

You could use parametrized fixtures and the importlib.reload function to test that environment variable is indeed used.

My test directory looks like this:

.
└── tests
    ├── conftest.py
    ├── dummy_api.py
    └── test_api.py

Here is my conftest.py:

import pytest
from fastapi.testclient import TestClient
from importlib import reload
import dummy_api


@pytest.fixture(params=["/get", "/dummy", "/other"])
def endpoint(request, monkeypatch):
    monkeypatch.setenv("ENDPOINT", request.param)
    return request.param


@pytest.fixture()
def client(endpoint):
    app = reload(dummy_api).app
    yield TestClient(app=app)

And here is the test_api.py file:

import os


def test_dummy_api(client):
    endpoint = os.environ["ENDPOINT"]
    response = client.get(endpoint)
    assert response.status_code == 200
    assert response.json() == {"message": f"Endpoint {endpoint} working !"}

Test output after running pytest:

collected 3 items                                                                                                                                    

tests/test_api.py::test_dummy_api[/get] PASSED                                                                                                   [ 33%]
tests/test_api.py::test_dummy_api[/dummy] PASSED                                                                                                  [ 66%]
tests/test_api.py::test_dummy_api[/other] PASSED                                                                                                  [100%]
Sign up to request clarification or add additional context in comments.

Comments

2

This is an approach I've taken - simply don't import app until after the env is set up.

@pytest.fixture
def client():
    os.environ['DB_URL'] = 'http://foobar:1111'

    from main import app  # Import only after env created
    yield TestClient(app)

def test_health_endpoint(client):
    response = client.get("/health")
    assert response.status_code == 200

Comments

-1

To me it looks like this:

  • When the test file is loaded by pytest then all things that can be executed in dummy_api will be executed because it is imported.
  • This means that the decorator of the decorated function (i.e. @app.get(...)) will be executed. At this point in time monkey-patching has not kicked in.
  • Once the test function kicks in, the environment variable has been set too late.

1 Comment

Any ideas how to change it ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.