Skip to content

filipsnastins/testcontainers-github-actions

Repository files navigation

testcontainers-github-actions

An example of how to run Testcontainers in CI pipelines. This example is using GitHub Actions, but the same ideas apply to other CI pipeline runners too.

Based on tomodachi-testcontainers and testcontainers-python.

Running Testcontainer tests in CI pipeline

To run Testcontainers in the CI pipeline, you'll need a container runtime installed on the CI server (GitHub Actions, Jenkins etc.). That's pretty much it!

Running Testcontainers in the CI shouldn't be much different from running them locally.

This example is using GitHub Actions, where the ubuntu-latest image has Docker Engine pre-installed, so no extra setup is needed.

Generally there're could be (probably there are more!) two approaches for running tests in CI pipelines:

1. Run tests directly on the CI server

Install programming language runtime and dependencies on the CI server, and run the tests directly on the CI server too. This approach example pipeline is in .github/workflows/build-and-test--on-ci-server.yml

  • That's very similar to how tests are run on a local machine.
  • This works really well with GitHub Actions, because after the workflow is finished, CI server is discarded and all the installed dependencies are removed, so the next workflow run starts from a clean state.
  • A downside for this approach: tests won't be running in the exactly the same environment as the production environment. To fix this, we can run the tests from inside the application's Docker container - the deployment environment.

Run tests directly on the CI server

2. Run tests from inside a Docker container

The application code, its dependencies and the test suite are first packaged into a Docker image, and the tests are run from inside the Docker container.

This approach example pipeline is in .github/workflows/build-and-test--with-dev-image.yml

  • CI server only needs a container runtime installed, no other dependencies are needed.

  • It usually requires a multi-stage Dockerfile with two stages:

    • Development - with development dependencies installed.
    • Release - with only production dependencies and production code.
  • This approach isolates how the tests are run from the mechanics of the specific CI server you're using - the tests are always run in the same way, in exactly the same environment as production, because it's the same Docker image.

  • How it works:

    • CI server runs a Docker image from the development stage, and runs the test command in the container.
    • However, since the application itself is tested as a (test)container, the container that's running the tests must be able to run new Docker containers.
    • This can be done with "Docker-from-Docker" method by mounting the Docker Unix socket from the host machine to the container. It will allow a container to run new containers on the host machine.
    • ⚠️ In the end-to-end tests, we want to test the exact same Docker image that's going to be deployed to production, so the tests must be ran against the release stage Docker image.
    • In case of tomodachi-testcontainers, use the environment variable TOMODACHI_TESTCONTAINER_IMAGE_ID to specify the image ID of the release stage.

Run tests from inside a Docker container

Resources

Development

  • Install dev dependencies with Poetry
poetry install
poetry shell
pre-commit install
  • Run tests
poetry run test
poetry run test-ci
  • Format and lint code
poetry run format
poetry run lint
  • Run all commit hooks at once
poetry run hooks