🎓 A1Learner
🔍
0 of 46 lessons completed

Elixir Async Tests

Async tests are tests that ExUnit may run at the same time as other tests. They suit tests that do not share changing state.

An async module holds ordinary tests

ExUnit starts with a fixed seed and no formatters. The module is marked async, and the script prints only its own counts.

ExUnit.start(seed: 0, auto_run: false, formatters: [])
defmodule AddTest do
  use ExUnit.Case, async: true

  test "adds two numbers" do
    assert 1 + 2 == 3
  end

  test "adds zero" do
    assert 5 + 0 == 5
  end
end
result = ExUnit.run()
IO.puts("passed: #{result.total - result.failures}/#{result.total}")

Two async modules share one run

Each module is marked async on its own. The single run counts the tests from both modules.

ExUnit.start(seed: 0, auto_run: false, formatters: [])
defmodule TripleTest do
  use ExUnit.Case, async: true

  test "triples a number" do
    assert 3 * 4 == 12
  end
end
defmodule HalfTest do
  use ExUnit.Case, async: true

  test "halves a number" do
    assert div(10, 2) == 5
  end
end
result = ExUnit.run()
IO.puts("passed: #{result.total - result.failures}/#{result.total}")

The run result carries the counts

The result of ExUnit.run is a map. The script prints its total and its failures from that map.

ExUnit.start(seed: 0, auto_run: false, formatters: [])
defmodule OneTest do
  use ExUnit.Case, async: true

  test "checks one fact" do
    assert String.upcase("ana") == "ANA"
  end
end
result = ExUnit.run()
IO.puts("total: #{result.total}")
IO.puts("failures: #{result.failures}")

Example

ExUnit.start(seed: 0, auto_run: false, formatters: [])
defmodule MathTest do
  use ExUnit.Case, async: true

  test "adds" do
    assert 2 + 3 == 5
  end

  test "multiplies" do
    assert 2 * 3 == 6
  end
end
defmodule WordTest do
  use ExUnit.Case, async: true

  test "upcases" do
    assert String.upcase("ana") == "ANA"
  end
end
result = ExUnit.run()
IO.puts("passed: #{result.total - result.failures}/#{result.total}")

Key points

  • ExUnit: start ExUnit once with ExUnit.start before any test module is defined.
  • Async: a test module marked async may run at the same time as other async modules.
  • Seed: a fixed seed makes the test order the same on every run.
  • Formatters: an empty formatter list stops ExUnit from printing its own report.
  • Counts: ExUnit.run returns a map with total and failures, so the script prints its own counts.

In this example, ExUnit starts with a fixed seed and no formatters, then two async modules are defined, one with two math tests and one with one word test. ExUnit.run runs all three tests, and the script prints the passed count from the result map.

Note

async tests must not share changing state, since they may run at the same time.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What does marking a test module async mean?