Elixir Testing with ExUnit
Elixir Testing with ExUnit
Testing is a fundamental part of the Elixir platform, powered by ExUnit. This guide will walk you through defining and running tests effectively.
Defining Tests in Mix Projects
If you are working within a Mix Application, the standard practice is to place your test files in the test
directory. These tests are automatically discovered and executed when you run the command mix test
from your project's root directory. Mix sets up the necessary environment for ExUnit to run your tests seamlessly.
Inline Tests
For simpler scenarios or quick checks, you can also define tests directly at the end of any Elixir file. These tests will be executed automatically during the compilation process of that file. This is a convenient way to ensure that specific code snippets behave as expected without needing a separate test file.
Test Boilerplate
A typical Elixir test file using ExUnit follows a specific structure. Here's a basic example:
# The ExUnit.start call is often handled automatically by Mix projects
# in a file like test_helper.exs. You may need it for standalone files.
# ExUnit.start
defmodule MyModuleTest do
use ExUnit.Case
test "should assert the truth" do
assert 1 + 1 == 2
end
test "another example test" do
refute is_nil(self())
end
end
Debugging Tests with IEx.pry
Debugging within the context of a running test is made easy with Elixir's interactive shell (IEx). Follow these steps to set up and use debugging:
-
At the top of your test file, before the
defmodule
declaration, add the following line to require IEx:require IEx
-
Inside your test function, at the exact point where you wish to pause execution and enter an IEx session, insert the following line:
IEx.pry()
-
Run your tests using a specific invocation that prevents timeouts and allows you to interact with the debugger. Replace
<test specification>
with a pattern to select specific tests if needed (e.g.,MyModuleTest
or"should assert the truth"
):iex -S mix test --trace <test specification>
The
--trace
flag is crucial as it ensures that IEx does not time out, allowing you to step through your code and inspect variables when you hitIEx.pry()
.