Skip to content

Testing Applications Built with other Frameworks like Flask, FastAPI, or Django

With Testcontainers, you can test any app running in a container.

Using the testcontainer_image pytest fixture, you can build a Docker image with Dockerfile from a current working directory. Then, you can use the built Docker image ID to start a new container. To learn how to create your new Testcontainers, see the previous guide - Creating new Testcontainers.

Below are examples of running Flask, FastAPI, and Django applications with Testcontainers. The specific framework doesn't matter as long as it runs in a container.

Flask example

src/flask_app.py
import os

from flask import Flask, Response, jsonify

app = Flask(__name__)


@app.route("/hello")
def hello_api() -> Response:
    greet = os.getenv("GREET", "stranger")
    return jsonify({"message": f"Hello from Flask, {greet}!"})


@app.route("/health")
def healthcheck_api() -> Response:
    return jsonify({"status": "ok"})
tests/test_flask_app.py
from typing import Generator

import pytest
import requests

from tomodachi_testcontainers import DockerContainer, WebContainer


class FlaskContainer(WebContainer):
    def __init__(self, image: str) -> None:
        super().__init__(
            image=image,
            internal_port=5000,
            http_healthcheck_path="/health",
        )

    def log_message_on_container_start(self) -> str:
        return f"Flask web app: http://localhost:{self.edge_port}"


@pytest.fixture(scope="session")
def flask_container(testcontainer_image: str) -> Generator[DockerContainer, None, None]:
    with (
        FlaskContainer(testcontainer_image)
        .with_env("GREET", "Testcontainers")
        .with_command("flask --app creating_testcontainers/flask_app.py run --host 0.0.0.0 --port 5000")
    ) as container:
        yield container


def test_greetings_from_flask(flask_container: FlaskContainer) -> None:
    base_url = flask_container.get_external_url()

    response = requests.get(f"{base_url}/hello", timeout=10)

    assert response.json() == {"message": "Hello from Flask, Testcontainers!"}

FastAPI example

src/fastapi_app.py
import os

from fastapi import FastAPI

app = FastAPI()


@app.get("/hello")
async def hello_api() -> dict:
    greet = os.getenv("GREET", "stranger")
    return {"message": f"Hello from FastAPI, {greet}!"}


@app.get("/health")
async def healthcheck_api() -> dict:
    return {"status": "ok"}
tests/test_fastapi_app.py
from typing import Generator

import pytest
import requests

from tomodachi_testcontainers import DockerContainer, WebContainer


class FastAPIContainer(WebContainer):
    def __init__(self, image: str) -> None:
        super().__init__(
            image,
            internal_port=8000,
            http_healthcheck_path="/health",
        )

    def log_message_on_container_start(self) -> str:
        return f"FastAPI web app: http://localhost:{self.edge_port}"


@pytest.fixture(scope="session")
def fastapi_container(testcontainer_image: str) -> Generator[DockerContainer, None, None]:
    with (
        FastAPIContainer(testcontainer_image)
        .with_env("GREET", "Testcontainers")
        .with_command("uvicorn creating_testcontainers.fastapi_app:app --host 0.0.0.0 --port 8000")
    ) as container:
        yield container


def test_greetings_from_fastapi(fastapi_container: FastAPIContainer) -> None:
    base_url = fastapi_container.get_external_url()

    response = requests.get(f"{base_url}/hello", timeout=10)

    assert response.json() == {"message": "Hello from FastAPI, Testcontainers!"}

Django example

src/django_app/django_app/views.py
import os

from django.http import HttpRequest, JsonResponse


def hello_api(request: HttpRequest) -> JsonResponse:
    greet = os.getenv("GREET", "stranger")
    return JsonResponse({"message": f"Hello from Django, {greet}!"})


def healthcheck_api(request: HttpRequest) -> JsonResponse:
    return JsonResponse({"status": "ok"})
tests/test_django_app.py
from typing import Generator

import pytest
import requests

from tomodachi_testcontainers import DockerContainer, WebContainer


class DjangoContainer(WebContainer):
    def __init__(self, image: str) -> None:
        super().__init__(
            image=image,
            internal_port=8000,
            http_healthcheck_path="/health",
        )

    def log_message_on_container_start(self) -> str:
        return f"Django web app: http://localhost:{self.edge_port}"


@pytest.fixture(scope="session")
def django_container(testcontainer_image: str) -> Generator[DockerContainer, None, None]:
    with (
        DjangoContainer(testcontainer_image)
        .with_env("GREET", "Testcontainers")
        .with_command("python creating_testcontainers/django_app/manage.py runserver 0.0.0.0:8000")
    ) as container:
        yield container


def test_greetings_from_django(django_container: DjangoContainer) -> None:
    base_url = django_container.get_external_url()

    response = requests.get(f"{base_url}/hello", timeout=10)

    assert response.json() == {"message": "Hello from Django, Testcontainers!"}