How do I write a test with the FastAPI framework which uses a fake implementation of some object which itself must exist for the lifespan of the app?

I am trying to write some FastAPI tests.

To be more specific, I am trying to write tests which tests the FastAPI endpoints which I have defined. (In the FastAPI docs endpoints are refered to as “paths”.)

The endpoints which I have defined call an object. This object (“service”) maintains, in memory, all data related to the application.

This design imposes some requirements. Either threads must not be used or some mechanism such as locks must be used to enforce mutual exclusion. I opted for the former, to make things simple:

  • The “service” must be accessed synchronously, which implies the endpoints must be async def. This ensures that a thread pool is not used.
  • await is not called anywhere. This has the effect of causing each async endpoint to behave in a synchronous manner.

I have written a MWE for demonstration purposes. Here is the file containing my “FastAPI related code” including definitions of the endpoints:

from fastapi import FastAPI
from fastapi import Request

from contextlib import asynccontextmanager

from implementation import Implementation


@asynccontextmanager
async def lifespan(app: FastAPI):
    async with AsyncClient(app=app) as client:
        implementation = Implementation()
        yield {'implementation': implementation}
        implementation.shutdown() # MUST be called!

app = FastAPI(lifespan=lifespan)


@app.post('/api/increment')
async def api_increment(
    request: Request,
):
    implementation: Implementation = request.state.implementation
    implementation.increment()
    return {}


@app.get('/api/get_value')
async def api_get_value(
    request: Request,
):
    implementation: Implementation = request.state.implementation
    value = implementation.get_value()
    return {
        'value': value,
    }

This conforms to the requirements I gave details of above. You can see that I have used the “lifespan” concept to ensure implementation persists for the lifespan of the application.

Implementation represents the “service”. There are two implementations of Implementation, a “real” one and a “fake” one which should be used when running the tests. (I have not yet built a full strategy pattern to present a single interface for both types, but this could be done very easily.)

Here is the “real” implementation of the “service”:

class Implementation():

    def __init__(self) -> None:
        self.current_value = 0
        self._initialized = True
        print(f'Implementation starts')

    def shutdown(self) -> None:
        '''
        A function which must be called to cleanup resources before exit
        '''
        self._initialized = False
        print(f'Implementation stops')

    def increment(self) -> None:
        '''
        In reality this would do something like read/write to a file, db etc
        '''
        self.current_value += 1

    def get_value(self) -> None:
        return self.current_value

And here is the “fake” implementation, which should be used in tests:

class ImplementationFake():

    def __init__(self) -> None:
        print(f'Implementation starts')

    def shutdown(self) -> None:
        '''
        A function which must be called to cleanup resources before exit
        (at least if the implementation being used is the real implementation
        - the fake implementation probably wouldn't do anything here)
        '''
        print(f'Implementation stops')

    def increment(self) -> None:
        pass

    def get_value(self) -> None:
        return 42

Finally, here is the file containing my test code:

import pytest

from fastapi.testclient import TestClient

from fastapi_webserver import app

def test_get_value():
    with TestClient(app) as client:
        response = client.get('/api/get_value')
        assert response.status_code == 200
        assert response.json() == {
            #'value': 0, # <- using REAL implementation
            'value': 42, # <- using FAKE implementation
        }

This test fails because the value 0 is returned by the “real” implementation. This would be fine for running in production, but not the expected behaviour when running the “service” from within a test code. The expected behaviour is the “fake” implementation returns the hardcoded value 42.

I understand that there are two relevant “ideas” relating to this question.

  1. The concept of lifespan contexts
  2. The concept of dependencies

My object must exist for the lifespan of the FastAPI application. This seems to suggest it has to be loaded using a lifespan context.

However, if I understand correctly, dependencies are usually expected to be handled with the Dependency concept. The Dependency concept can be used to switch between a real and fake implementation of some object for testing purposes.

I do not understand how to combine these two idea. Could someone explain how to do so?

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật