Skip to content

nshkrdotcom/supertester

Repository files navigation

Supertester

Supertester Logo

Hex.pm Documentation Build Status License

A battle-hardened OTP testing toolkit with chaos engineering, performance testing, and zero-sleep synchronization for building robust Elixir applications.

Version 0.2.1 - Now with chaos engineering, performance testing, and supervision tree testing!


The Problem: Flaky OTP Tests

Are you tired of...

  • 😫 Flaky tests that fail randomly due to race conditions?
  • πŸ“› GenServer name clashes when running tests with async: true?
  • πŸ•°οΈ Littering your test suite with Process.sleep/1 and hoping for the best?
  • πŸ€·β€β™‚οΈ Struggling to test process crashes, restarts, and complex supervision trees?

Writing tests for concurrent systems is hard. Traditional testing methods often lead to fragile, non-deterministic, and slow test suites.

The Solution: Supertester

Supertester provides a comprehensive suite of tools to write clean, deterministic, and reliable tests for your OTP applications. It replaces fragile timing hacks with robust synchronization patterns and provides powerful helpers for simulating and asserting complex OTP behaviors.

With Supertester, you can build a test suite that is fast, parallel, and trustworthy.

Key Features

  • βœ… Rock-Solid Test Isolation: Run all your tests with async: true without fear of process name collisions or state leakage.
  • πŸ”„ Zero Process.sleep: Complete elimination of timing-based synchronization. Use proper OTP patterns for deterministic testing.
  • πŸ€– Powerful OTP Assertions: Go beyond assert. Use assert_process_restarted/2, assert_genserver_state/2, and assert_all_children_alive/1 for more expressive tests.
  • ✨ Effortless Setup & Teardown: Start isolated GenServers and Supervisors with a single line and trust Supertester to handle all the cleanup.
  • πŸ’₯ Chaos Engineering: Test system resilience with controlled fault injection, random process crashes, and resource exhaustion.
  • 🎯 Supervision Tree Testing: Verify restart strategies, trace supervision events, and validate tree structures.
  • ⚑ Performance Testing: Assert performance SLAs, detect memory leaks, and prevent regressions with built-in benchmarking.
  • πŸ”§ TestableGenServer: Automatic injection of sync handlers for deterministic async operation testing.

Installation

Add supertester as a dependency in your mix.exs file. It's only needed for the :test environment.

def deps do [ {:supertester, "~> 0.2.1", only: :test} ] end

Then, run mix deps.get to install.

Quick Start: From Flaky to Robust

See how Supertester transforms a common, fragile test pattern into a robust, deterministic one.

Before: The Flaky Way

# test/my_app/counter_test.exs defmodule MyApp.CounterTest do use ExUnit.Case, async: false # <-- Forced to run sequentially test "incrementing the counter" do # Manual setup, prone to name conflicts {:ok, _pid} = start_supervised({Counter, name: Counter}) GenServer.cast(Counter, :increment) Process.sleep(50) # <-- Fragile, timing-dependent guess state = GenServer.call(Counter, :state) assert state.count == 1 end end

After: The Supertester Way

# test/my_app/counter_test.exs defmodule MyApp.CounterTest do use ExUnit.Case, async: true # <-- Fully parallel! # Import the tools you need import Supertester.OTPHelpers import Supertester.GenServerHelpers import Supertester.Assertions test "incrementing the counter" do # Isolated setup with automatic cleanup, no name clashes {:ok, counter_pid} = setup_isolated_genserver(Counter) # Deterministic sync: ensures the cast is processed before continuing :ok = cast_and_sync(counter_pid, :increment) # Expressive, OTP-aware assertion for checking state assert_genserver_state(counter_pid, fn state -> state.count == 1 end) end end

Core Modules Overview

Supertester is organized into several powerful modules, each targeting a specific area of OTP testing.

  • Supertester.UnifiedTestFoundation: The cornerstone of test isolation. Use it in your test cases to create a sandboxed environment, enabling safe concurrent testing with automatic cleanup of processes and ETS tables.

  • Supertester.TestableGenServer: A simple behavior to make your GenServers more testable. It automatically injects handlers to allow deterministic synchronization in your tests, completely eliminating the need for Process.sleep/1.

  • Supertester.OTPHelpers: Provides the essential tools for managing the lifecycle of isolated OTP processes. Functions like setup_isolated_genserver/3 and setup_isolated_supervisor/3 are your entry point for starting processes within the isolated test environment.

  • Supertester.GenServerHelpers: Contains specialized functions for interacting with GenServers. The star of this module is cast_and_sync/2, which provides a robust way to test asynchronous cast operations deterministically. It also includes helpers for stress-testing and crash recovery scenarios.

  • Supertester.SupervisorHelpers: A dedicated toolkit for testing the backbone of OTP applications: supervisors. You can verify restart strategies, validate supervision tree structures, and trace supervision events to ensure your application is truly fault-tolerant.

  • Supertester.ChaosHelpers: Unleash controlled chaos to test your system's resilience. This module allows you to inject faults, kill random processes, and simulate resource exhaustion to ensure your system can withstand turbulent conditions.

  • Supertester.PerformanceHelpers: Integrate performance testing directly into your test suite. Assert that your code meets performance SLAs, detect memory leaks, and prevent performance regressions before they hit production.

  • Supertester.Assertions: A rich set of custom assertions that understand OTP primitives. Go beyond simple equality checks with assertions like assert_genserver_state/2, assert_all_children_alive/1, and assert_no_process_leaks/1 for more expressive and meaningful tests.

Advanced Usage Examples

Chaos Engineering

Test your system's resilience to failures:

test "system survives random process crashes" do {:ok, supervisor} = setup_isolated_supervisor(MyApp.WorkerSupervisor) # Kill 50% of workers over 3 seconds report = chaos_kill_children(supervisor, kill_rate: 0.5, duration_ms: 3000, kill_interval_ms: 200 ) # Verify system recovered assert Process.alive?(supervisor) assert report.supervisor_crashed == false assert_all_children_alive(supervisor) end

Performance Testing

Ensure your code meets performance SLAs:

test "API response time SLA" do {:ok, api_server} = setup_isolated_genserver(APIServer) assert_performance( fn -> APIServer.handle_request(api_server, :get_user) end, max_time_ms: 50, max_memory_bytes: 500_000, max_reductions: 100_000 ) end test "no memory leak in message processing" do {:ok, worker} = setup_isolated_genserver(MessageWorker) assert_no_memory_leak(10_000, fn -> MessageWorker.process(worker, generate_message()) end) end

Supervision Tree Testing

Verify supervision strategies work correctly:

test "one_for_one restarts only failed child" do {:ok, supervisor} = setup_isolated_supervisor(MySupervisor) result = test_restart_strategy(supervisor, :one_for_one, {:kill_child, :worker_1} ) assert result.restarted == [:worker_1] assert :worker_2 in result.not_restarted assert :worker_3 in result.not_restarted end test "supervision tree structure" do {:ok, root} = setup_isolated_supervisor(RootSupervisor) assert_supervision_tree_structure(root, %{ supervisor: RootSupervisor, strategy: :one_for_one, children: [ {:cache, CacheServer}, {:worker_pool, WorkerPoolSupervisor} ] }) end

Documentation

For a comprehensive guide to all features, modules, and functions, please see the full User Manual.

The user manual includes:

  • In-depth explanations of every module.
  • Detailed function signatures, parameters, and return values.
  • Practical code examples and recipes for common testing scenarios.
  • Best practices for writing robust tests.

Additional documentation, including the technical design, can be found in the docs/ directory.

What's New in 0.2.0

  • πŸŽ‰ Zero Process.sleep: Eliminated all timing-based synchronization
  • πŸŽ‰ ChaosHelpers: Complete chaos engineering toolkit
  • πŸŽ‰ PerformanceHelpers: Performance testing and regression detection
  • πŸŽ‰ SupervisorHelpers: Comprehensive supervision tree testing
  • πŸŽ‰ TestableGenServer: Automatic sync handler injection
  • πŸŽ‰ 37 tests: All passing with 100% async execution

See CHANGELOG.md for detailed changes.

Contributing

Contributions are welcome! If you'd like to help improve Supertester, please feel free to:

  1. Fork the repository.
  2. Create a new feature branch.
  3. Add your feature or bug fix.
  4. Ensure all new code is covered by tests.
  5. Open a pull request.

License

This project is licensed under the MIT License.

Packages

No packages published

Contributors 3

  •  
  •  
  •