View Source ExUnit Atlas

Quality License: MIT

ExUnit Atlas turns ordinary ExUnit tests into a readable map of the behavior your application guarantees.

It is not a new test framework. ExUnit remains responsible for tests, assertions, failures, stacktraces, terminal output, and exit codes. Atlas adds three small annotations—step, show, and check—and generates:

ex_unit_atlas_report/
├── report.json
└── index.html

The HTML report is a self-contained document with no server, JavaScript, external assets, or frontend build step.

Why Atlas?

Test names are useful, but a test often guarantees more than its name can say. Atlas lets the test body expose those guarantees without replacing familiar ExUnit structure:

ExUnitAtlas interpretation
module or filebehavior group
describebehavior section
testscenario
stepmeaningful setup or action
showbounded preview of data flowing through the scenario
checknamed guarantee
ExUnit resultscenario status

The resulting report is meant to be read from top to bottom as business behavior, while technical metadata remains available when needed.

Installation

Add Atlas as a test-only dependency:

def deps do
  [
    {:ex_unit_atlas, "~> 0.2.0", only: :test, runtime: false}
  ]
end

Run mix deps.get.

In test/test_helper.exs, replace the existing ExUnit.start() call with:

ExUnit.start(
  formatters: [
    ExUnit.CLIFormatter,
    ExUnitAtlas.Formatter
  ]
)

Keep the standard CLI formatter. Atlas complements it; it does not print the normal test results.

Usage

Add use ExUnitAtlas after use ExUnit.Case or your project-specific case template:

defmodule Shop.SaleTest do
  use ExUnit.Case, async: true
  use ExUnitAtlas

  describe "Sales" do
    test "cash sales are fiscalized" do
      sale =
        step "Create a completed cash sale" do
          %{payment_type: :cash, status: :completed}
        end
        |> show("Created sale")

      check "The completed cash sale is eligible for fiscalization" do
        assert sale.payment_type == :cash
        assert sale.status == :completed
      end
    end
  end
end

Run tests normally:

mix test

Open ex_unit_atlas_report/index.html in a browser, or consume ex_unit_atlas_report/report.json from another tool.

Showing data as it flows

show/2 records a bounded inspect preview and returns the original value, so it fits naturally into pipelines:

order
|> calculate_totals()
|> show("Order after totals")
|> apply_discount()
|> show("Order after discount")
|> persist()

The report displays each preview between the surrounding steps and checks. It does not serialize the original term: collections, strings, and the final preview are limited to keep reports readable.

Do not show credentials, tokens, personal data, or other secrets. Report files are often retained as CI artifacts.

Choosing useful annotations

Use a step for preparation or an action that carries business meaning. Use a check to name a guarantee and keep regular assert and refute expressions inside it.

Do not add a step only because every scenario appears to need one. This is perfectly valid:

test "disabled fiscalization overrides the request" do
  check "Fiscalization remains disabled" do
    refute should_fiscalize?(request, %{fiscalization_type: :disabled})
  end
end

The report becomes valuable when names explain behavior—not when every line of test code receives a label.

Runtime semantics

  • Instrumented blocks execute exactly once.
  • Their return values are returned unchanged.
  • show returns the exact input value and records only a bounded string preview.
  • error, exit, and throw retain their original reason and stacktrace.
  • Assertion messages and useful user frames remain visible.
  • Concurrent tests keep independent, ordered item streams.
  • Passing and failing suites both produce reports.
  • ExUnit keeps control of terminal output and the process exit status.
  • Without ExUnitAtlas.Formatter, blocks still execute normally but no report is generated.

Current limitations

  • Nested step, show, and check items are rejected.
  • The output directory is fixed to ex_unit_atlas_report.
  • Skipped and excluded tests are omitted from schema version 2.
  • Logger output is not captured; use show for intentional data previews.
  • Atlas does not automatically register its formatter.

Documentation

Requirements

  • Elixir 1.14 or later
  • OTP 25 or later is the currently verified baseline
  • No runtime dependencies

Contributing

Bug reports and focused improvements are welcome. Read CONTRIBUTING.md before opening a pull request. By participating, you agree to follow the Code of Conduct.

For release validation and publication, see RELEASING.md.

License

ExUnit Atlas is available under the MIT License.