Testcontainers is an Elixir library that supports ExUnit tests, providing lightweight, throwaway instances of common databases, or anything else that can run in a Docker container.
It supports Testcontainers Desktop, but doesn’t need it to run. It will find and pick up a docker engine that works every time it runs.
But the most interesting usage for Elixir is the Ecto module, which lets you run tests without having a postgres (or mysql) container running (see the README section for this advanced usage).
You can also spin up a throwaway container in a single ExUnit test:
It has a dependency on an autogenerated elixir library for the docker engine api. The complex logic for calling out to docker is hidden inside that library.
new version v1.3.0 released which dynamically sets host port in repo config when using Testcontainers.Ecto No more duplication of database options see here for more info
In its core it allows for spinning up containers in tests. I have additionally added support for running a database container in dev and test in Phoenix. I use this approach myself in all projects i work on lately. And it saves a lot of frustration not having to give the slightest thought about how the database is created. We use mix test.watch to automatically rerun test suites, and i cant say it takes that long to start the container. I think right now the bottleneck is the database startup, but we only have 170 simple tests which completes in sub second. For larger Phoenix projects and those with sync tests i would expect the tests being the bottle neck.
I am going to add some timing logs on container startup but i wouldnt use too much time on that. We use alpine version of postgres if remember correctly.
The readme has been improved a lot recently. So the example in the original post is outdated and just wrong. Not possible to compile for release when using Mix module in application.ex. So use the GitHub repo readme as example on how to do it properly.
The Ecto approach does run migrations each time tests are run or each time app is started. But it supports an option persistent_volume_name that makes it possible to run Phoenix in dev mode with persistent changes.
I dont understand the isolation question 100% but all containers use dynamic and random ports. And there is no reuse.
however, there is an alternative way to solve this though. You can easily start the phoenix application in interactive elixir shell with iex -S mix phx.server and run Code.eval_file("priv/repo/seeds.exs") in the interactive terminal.
This is supoorted by Testcontainers. There are docs on using podman on the Golang language docs on testcontainers.com. Testcontainers for elixir will work with any docker runtime given it can find a docker host. And it uses several strategies
That’s cool. I wonder if it is possible to have concurrent tests, where each of those tests is running in an isolated database container. As far as I know, Ecto can spawn only one connections pool, that is using one port
Testcontainers for Elixir has module Testcontainers.Ecto. The purpose of this is to start a container, override ecto repo config and shutdown repo and container on system/test exit. The module will temporarely override the configured port with the dynamic host port of the container. So technically (not tested) if you have multiple repos you can run postgres_container for each repo.
I meant to ask if it is possible to run two or more tests at the same, while both of them are using the same Repo module, but each of this tests is connected to it’s own testcontainer with db. I guest that it is not possible, since Ecto Repo is a singletone, right?
Not really an answer to your exact question, but we had a similar issue of running tests in parallel in my last job, and we solved it by using a different database for each db connection in the pool.
Initially I was going to suggest configure option to switch server, but realized that configure hook only comes into play after it is connected to DB, so we can’t really use it to switch different db server running at different port
UPDATE: on second look, you should be able to configure to switch to a different DB server running on a different port for every connection (haven’t tested)
Maybe you could outline the problem a bit more ? In GitHub actions you can run the tests in partitions, effectively in parallell.
EDIT: You dont have to use partitioning on database name with Testcontainers. Its a new database for each time tests is run in GitHub actions. So Even if its the same database name in every parallell workflow run its different database server