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 !!

Subhayan Bhattacharya
  • 5,407
  • 7
  • 42
  • 60

2 Answers2

6

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%]
gcharbon
  • 1,561
  • 12
  • 20
-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.
Gros Lalo
  • 1,078
  • 7
  • 20