Testing with Ecto
After you have successfully set up your database connection with Ecto for your application, its usage for your tests requires further changes, especially if you want to leverage the Ecto SQL Sandbox that allows you to run tests that talk to the database concurrently.
Create the config/test.exs
file or append the following content:
use Mix.Config
config :my_app, MyApp.Repo,
username: "postgres",
password: "postgres",
database: "myapp_test",
hostname: "localhost",
pool: Ecto.Adapters.SQL.Sandbox
Thereby, we configure the database connection for our test setup. In this case, we use a Postgres database and set it up to use the sandbox pool that will wrap each test in a transaction.
Make sure we import the configuration for the test environment at the very bottom of config/config.exs
:
import_config "#{Mix.env()}.exs"
We also need to add an explicit statement to the end of test/test_helper.exs
about the sandbox
mode:
Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, :manual)
Lastly, you need to establish the database connection ahead of your tests.
You can enable it either for all of your test cases by extending the ExUnit
template or by setting it up individually for each test. Let's start with the former and place it to the test/support/repo_case.ex
:
defmodule MyApp.RepoCase do
use ExUnit.CaseTemplate
using do
quote do
alias MyApp.Repo
import Ecto
import Ecto.Query
import MyApp.RepoCase
# and any other stuff
end
end
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()})
end
:ok
end
end
The case template above brings Ecto
and Ecto.Query
functions into your tests and checkouts a database connection. It also enables a shared sandbox connection mode in case the test is not running asynchronously.
See Ecto.Adapters.SQL.Sandbox
for more information.
To add test/support/
folder for compilation in test environment we need to update mix.exs
configuration
def project do
[
# ...
elixirc_paths: elixirc_paths(Mix.env())
]
end
# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
And then in each test that uses the repository:
defmodule MyApp.MyTest do
use MyApp.RepoCase
# Tests etc...
end
In case you don't want to define a "case template", you can checkout on each individual case:
defmodule MyApp.MyTest do
use ExUnit.Case
setup do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo)
end
# Tests etc...
end
For convenience reasons, you can also define aliases
to automatically set up your database at the execution of your tests.
Change the following content in your mix.exs
.
def project do
[app: :my_app,
...
aliases: aliases()]
end
defp aliases do
[ ...
"test": ["ecto.create --quiet", "ecto.migrate", "test"]
]
end