Supertester.OTPHelpers (supertester v0.1.0)
View SourceOTP-compliant testing utilities for GenServer, Supervisor, and process management.
This module provides helpers that replace timing-based synchronization (Process.sleep) with proper OTP synchronization patterns, enabling reliable async testing.
Key Features
- Unique process naming to prevent conflicts
- OTP-compliant synchronization without Process.sleep
- Automatic resource cleanup
- Process lifecycle management
- Supervision tree testing utilities
Usage
import Supertester.OTPHelpers
test "my genserver test" do
{:ok, server} = setup_isolated_genserver(MyGenServer, "test_context")
assert_genserver_responsive(server)
end
Summary
Functions
Registers a cleanup function to run on test exit.
Cleans up a list of processes safely.
Monitors a process lifecycle and returns monitoring information.
Sets up an isolated GenServer with unique naming and automatic cleanup.
Sets up an isolated Supervisor with unique naming and automatic cleanup.
Waits for a GenServer to be synchronized and responsive.
Waits for a process to terminate.
Waits for a process to restart after termination.
Waits for a supervisor to finish starting all its children.
Functions
@spec cleanup_on_exit((-> any())) :: :ok
Registers a cleanup function to run on test exit.
Parameters
cleanup_fun
- Function to call on test exit
Example
cleanup_on_exit(fn -> GenServer.stop(my_server) end)
@spec cleanup_processes([pid()]) :: :ok
Cleans up a list of processes safely.
Parameters
pids
- List of PIDs to clean up
Example
cleanup_processes([pid1, pid2, pid3])
Monitors a process lifecycle and returns monitoring information.
Parameters
pid
- The process to monitor
Returns
{monitor_ref, pid}
Example
{ref, pid} = monitor_process_lifecycle(server_pid)
Sets up an isolated GenServer with unique naming and automatic cleanup.
Parameters
module
- The GenServer module to starttest_name
- Test context for unique naming (optional)opts
- Options passed to GenServer.start_link (optional)
Returns
{:ok, server_pid}
or {:error, reason}
Example
{:ok, server} = setup_isolated_genserver(MyGenServer, "my_test", [initial_state: %{}])
Sets up an isolated Supervisor with unique naming and automatic cleanup.
Parameters
module
- The Supervisor module to starttest_name
- Test context for unique naming (optional)opts
- Options passed to Supervisor.start_link (optional)
Returns
{:ok, supervisor_pid}
or {:error, reason}
Example
{:ok, supervisor} = setup_isolated_supervisor(MySupervisor, "my_test")
@spec wait_for_genserver_sync(GenServer.server(), timeout()) :: :ok | {:error, term()}
Waits for a GenServer to be synchronized and responsive.
Uses GenServer.call with a sync message instead of Process.sleep.
Parameters
server
- The GenServer pid or nametimeout
- Timeout in milliseconds (default: 1000)
Returns
:ok
if server is responsive, {:error, reason}
otherwise
Example
wait_for_genserver_sync(server, 5000)
Waits for a process to terminate.
Parameters
pid
- The process to wait fortimeout
- Timeout in milliseconds (default: 1000)
Returns
{:ok, reason}
if process died, {:error, :timeout}
if timeout
Example
ref = Process.monitor(pid)
Process.exit(pid, :kill)
{:ok, :killed} = wait_for_process_death(pid)
Waits for a process to restart after termination.
Parameters
process_name
- The registered name of the processoriginal_pid
- The PID before restarttimeout
- Timeout in milliseconds (default: 1000)
Returns
{:ok, new_pid}
if process restarted, {:error, reason}
otherwise
Example
original_pid = GenServer.whereis(MyServer)
GenServer.stop(MyServer)
{:ok, new_pid} = wait_for_process_restart(MyServer, original_pid)
@spec wait_for_supervisor_restart(Supervisor.supervisor(), timeout()) :: {:ok, pid()} | {:error, term()}
Waits for a supervisor to finish starting all its children.
Parameters
supervisor
- The supervisor pid or nametimeout
- Timeout in milliseconds (default: 1000)
Returns
:ok
if supervisor is ready, {:error, reason}
otherwise
Example
{:ok, supervisor} = setup_isolated_supervisor(MySupervisor)
wait_for_supervisor_restart(supervisor)