liveBook · Manning

Testcontainers

As explained in Build Financial Software with Generative AI (From Scratch)

Testcontainers is a library for creating and managing disposable containerized dependencies for automated tests.

Testcontainers provides temporary Docker containers for test dependencies such as a database. Each test can start with a fresh database and discard it when the test ends, rather than relying on a shared local container or manually clearing tables. This makes database-backed tests isolated, self-contained, and more reliable. section 8.4.1 section 10.8

A shared test database becomes harder to manage as tables and seed data grow. Truncation scripts may need exceptions for reference tables, and repeated runs can retain data or require infrastructure to be running first. Testcontainers shifts that cleanup responsibility to the container lifecycle, avoiding developer-specific setup and supporting CI/CD execution. section 5.2.1 section 8.4.1 section 10.2.3

Use Testcontainers when a test must exercise the real database behavior:

  • Start a database container before the test scope and stop it afterward. section 10.2.3
  • Run the API or database operation against the fresh container rather than a pre-existing local database. section 10.2.3
  • Keep the test self-contained so teammates and CI/CD pipelines can run it without matching local configuration. section 10.2.3 section 10.8

Testing a company API with a fresh database

A module-scoped pytest fixture opens a DockerCompose context, starts the database container, yields it to the test, and stops it afterward. The test creates a FastAPI TestClient, requests GET /api/v1/companies, and asserts a 200 response. Container startup supplies the database state that the endpoint needs without requiring a separately running local service. section 10.2.3

Listing 10.9 Initial unit test with Testcontainers
…
@pytest.fixture(scope="class") #1
def client():  #1
    return TestClient(app)  #1


@pytest.fixture(scope="module") #2
def docker_compose():   #2
    absolute_path = Path("../../../../docker/db").resolve()  #2
    with DockerCompose(absolute_path) as compose:  #2
        compose.start()  #2
        yield compose #2
        compose.stop()  #2
 
 
class TestCompanyApis:

    @pytest.fixture(autouse=True) #3
    def mock_client_host(self):  #3
        with patch(  #3
            "fastapi.Request.client",  #3
            new_callable=lambda: type("Client", (),   #3
                             {"host": "127.0.0.1"}),  #3
        ):  #3
            yield #3
 
    def test_get_companies(self, client, docker_compose): #4
        response = client.get("/api/v1/companies")  #4
        assert response.status_code == 200, response.text #4

The fixture shows the essential lifecycle: enter DockerCompose, start the service, run the test, then stop the service. section 10.2.3

Testcontainers complements rather than replaces mocking. A mock can remove the database dependency, but it cannot verify that records actually reach the database. Choose an isolated container when database integration is the behavior under test; consider mocking when that integration is outside the test’s purpose. section 5.2.1

How Build Financial Software with Generative AI (From Scratch) covers it

How deep it goes
Demonstrates a pytest DockerCompose fixture that starts and stops a fresh database for an API status test.
Examples
Uses a DockerCompose pytest fixture to test GET /api/v1/companies against a fresh database.
What it assumes
Assumes pytest, Docker containers, and database-backed tests; introduces the container lifecycle through a fixture.
What you can do after
Operate/configure it to run self-contained database-backed tests without a developer-specific running container.
How it connects
Connects Testcontainers with Docker Compose, pytest, CI/CD, mocking, database truncation, and API testing.

Also explained in

Compare how 5 books explain Testcontainers →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Build Financial Software with Generative AI (From Scratch). The section links point to the parts of the book it draws on.