Version: 0.6.0 Last Updated: March 3, 2026
This guide documents the main public APIs and behavior-sensitive edge cases.
Core
Supertester.version/0
@spec version() :: String.t()Supertester.ExUnitFoundation
use Supertester.ExUnitFoundation, isolation: :full_isolationOptions:
:isolation-:basic | :registry | :full_isolation | :contamination_detection:telemetry_isolation:logger_isolation:ets_isolation
Supertester.Env
Environment abstraction for test runner integration. By default delegates to ExUnit.Callbacks.on_exit/1.
@callback on_exit((-> any())) :: :ok
@spec on_exit((-> any())) :: :okOverride via application config:
config :supertester, env_module: MyApp.CustomTestEnvCustom implementation example:
defmodule MyApp.CustomTestEnv do
@behaviour Supertester.Env
@impl true
def on_exit(callback) when is_function(callback, 0) do
MyHarness.register_cleanup(callback)
end
endThe default implementation (Supertester.Env.ExUnit) calls ExUnit.Callbacks.on_exit/1.
OTP Helpers
Supertester.OTPHelpers
@spec setup_isolated_genserver(module(), String.t(), keyword()) :: {:ok, pid()} | {:error, term()}
@spec setup_isolated_supervisor(module(), String.t(), keyword()) :: {:ok, pid()} | {:error, term()}
@spec wait_for_genserver_sync(GenServer.server(), timeout()) :: :ok | {:error, term()}
@spec wait_for_process_restart(atom(), pid(), timeout()) :: {:ok, pid()} | {:error, term()}
@spec wait_for_supervisor_restart(Supervisor.supervisor(), timeout()) :: {:ok, pid()} | {:error, term()}
@spec monitor_process_lifecycle(pid()) :: {reference(), pid()}
@spec wait_for_process_death(pid(), timeout()) :: {:ok, term()} | {:error, :timeout}
@spec cleanup_processes([pid()]) :: :ok
@spec cleanup_on_exit((-> any())) :: :okProcess names are generated as {:via, Registry, {:supertester_shared_registry, ...}} tuples to avoid dynamic atom creation while ensuring async-safe uniqueness.
Supertester.GenServerHelpers
@spec get_server_state_safely(GenServer.server()) :: {:ok, term()} | {:error, term()}
@spec call_with_timeout(GenServer.server(), term(), timeout()) :: {:ok, term()} | {:error, term()}
@spec cast_and_sync(GenServer.server(), term(), term(), keyword()) :: :ok | {:ok, term()} | {:error, term()}
@spec concurrent_calls(GenServer.server(), [term()], pos_integer(), keyword()) :: {:ok, [map()]}
@spec stress_test_server(GenServer.server(), [term()], pos_integer(), keyword()) :: {:ok, map()}
@spec test_server_crash_recovery(GenServer.server(), term()) :: {:ok, map()} | {:error, term()}
@spec test_invalid_messages(GenServer.server(), [term()]) :: {:ok, [{term(), term()}]}cast_and_sync/4 semantics:
- When the sync handler replies
:ok(the defaultTestableGenServerbehavior), returns bare:ok. When it replies with any other value, returns{:ok, reply}. - missing sync support:
strict?: trueraisesArgumentError.strict?: falsereturns{:error, :missing_sync_handler}.
- covers missing-handler crashes raised as both runtime and function-clause exit shapes.
Supertester.TestableGenServer
Injects sync handlers via @before_compile macro:
handle_call(:__supertester_sync__, ...)— replies:okhandle_call({:__supertester_sync__, opts}, ...)— replies:okor{:ok, state}whenreturn_state: true
Usage: add use Supertester.TestableGenServer after use GenServer in your module.
Supervisor Helpers
Supertester.SupervisorHelpers
@spec test_restart_strategy(Supervisor.supervisor(), atom(), restart_scenario()) :: test_result()
@spec trace_supervision_events(Supervisor.supervisor(), keyword()) :: {:ok, (-> [supervision_event()])}
@spec assert_supervision_tree_structure(Supervisor.supervisor(), tree_structure()) :: :ok
@spec wait_for_supervisor_stabilization(Supervisor.supervisor(), timeout()) :: :ok | {:error, :timeout}
@spec get_active_child_count(Supervisor.supervisor()) :: non_neg_integer()Behavior notes:
test_restart_strategy/3validates strategy at runtime and raises on mismatch or unknown scenario child IDs.- removed temporary children are not classified as restarted.
assert_supervision_tree_structure/2validates supervisor module, strategy, and child modules when specified.
Chaos
Supertester.ChaosHelpers
@spec inject_crash(pid(), crash_spec(), keyword()) :: :ok
@spec chaos_kill_children(Supervisor.supervisor(), keyword()) :: chaos_report()
@spec simulate_resource_exhaustion(atom(), keyword()) :: {:ok, (-> :ok)} | {:error, term()}
@spec assert_chaos_resilient(pid(), (-> any()), (-> boolean()), keyword()) :: :ok
@spec run_chaos_suite(pid(), [map()], keyword()) :: chaos_suite_report()Behavior notes:
chaos_kill_children/2accepts pid and registered supervisor names (atom,{:global, _},{:via, _, _}).restartedcounts observed child replacements, including cascade replacements.run_chaos_suite/3:- applies suite deadline with
:timeoutand:suite_timeoutwhen execution overruns. - does not treat ordinary scenario failures with reason
:timeoutas suite timeout cutoffs.
- applies suite deadline with
Assertions
Supertester.Assertions
@spec assert_process_alive(pid()) :: :ok
@spec assert_process_dead(pid()) :: :ok
@spec assert_process_restarted(atom(), pid()) :: :ok
@spec assert_genserver_state(GenServer.server(), term() | (term() -> boolean())) :: :ok
@spec assert_genserver_responsive(GenServer.server()) :: :ok
@spec assert_genserver_handles_message(GenServer.server(), term(), term()) :: :ok
@spec assert_supervisor_strategy(Supervisor.supervisor(), atom()) :: :ok
@spec assert_child_count(Supervisor.supervisor(), non_neg_integer()) :: :ok
@spec assert_all_children_alive(Supervisor.supervisor()) :: :ok
@spec assert_memory_usage_stable((-> any()), float()) :: :ok
@spec assert_no_process_leaks((-> any())) :: :ok
@spec assert_performance_within_bounds(map(), map()) :: :okassert_supervisor_strategy/2 validates the runtime supervisor strategy by introspecting internal state. Works with both standard Supervisors (tuple-based state) and DynamicSupervisors (map-based state).
assert_no_process_leaks/1:
- traces spawned/linked descendants attributable to the operation.
- catches delayed descendant leaks.
- ignores short-lived transient processes.
- propagates exceptions from the operation.
Performance
Supertester.PerformanceHelpers
@spec assert_performance((-> any()), keyword()) :: :ok
@spec assert_expectations(map(), keyword()) :: :ok
@spec assert_no_memory_leak(pos_integer(), (-> any()), keyword()) :: :ok
@spec measure_operation((-> any())) :: map()
@spec measure_mailbox_growth(pid(), (-> any()), keyword()) :: map()
@spec assert_mailbox_stable(pid(), keyword()) :: :ok
@spec compare_performance(map()) :: map()Concurrency and Diagnostics
Supertester.ConcurrentHarness
@spec run(scenario()) :: {:ok, map()} | {:error, term()}
@spec run_with_performance(scenario(), keyword()) :: {:ok, map()} | {:error, term()}
@spec simple_genserver_scenario(module(), [term() | operation()], pos_integer(), keyword()) :: Scenario.t()
@spec from_property_config(module(), map(), keyword()) :: Scenario.t()
@spec chaos_kill_children(keyword()) :: chaos_fun()
@spec chaos_inject_crash(ChaosHelpers.crash_spec(), keyword()) :: chaos_fun()Supertester.PropertyHelpers
StreamData-based operation/scenario generators.
Supertester.MessageHarness
@spec trace_messages(pid(), (-> any()), keyword()) :: %{
messages: [term()],
result: term(),
initial_mailbox: [term()],
final_mailbox: [term()]
}Supertester.Telemetry and Supertester.TelemetryHelpers
Telemetry namespace and per-test telemetry isolation helpers.
Supertester.LoggerIsolation and Supertester.ETSIsolation
Per-test logger/ETS isolation helpers.