Hooks
May 15, 2026 · View on GitHub
Mutant provides a hooks system that allows to inject custom behavior at critical points in the mutation testing execution pipeline. This is useful for setting up worker-specific resources, instrumenting mutations, or customizing the testing environment.
Available Hooks
Mutant provides 8 different hook types that fire at various stages of execution:
Environment Hooks
env_infection_pre- Runs before environment infection (loading requires/includes)- Payload:
env:(theMutant::Envobject)
- Payload:
env_infection_post- Runs after environment infection- Payload:
env:(theMutant::Envobject)
- Payload:
Integration Setup Hooks
setup_integration_pre- Runs before test integration setup- Payload: None
setup_integration_post- Runs after test integration setup- Payload: None
Mutation Hooks
mutation_insert_pre- Runs before a mutation is inserted into the code- Payload:
mutation:(theMutant::Mutationobject)
- Payload:
mutation_insert_post- Runs after a mutation is inserted- Payload:
mutation:(theMutant::Mutationobject)
- Payload:
Worker Process Hooks
mutation_worker_process_start- Runs when a mutation worker process starts- Payload:
index:(the worker process index number)
- Payload:
test_worker_process_start- Runs when a test worker process starts- Payload:
index:(the worker process index number)
- Payload:
Configuration
Hooks are configured in your mutant configuration file (.mutant.yml, config/mutant.yml, or mutant.yml) by specifying paths to hook files:
---
hooks:
- path/to/hooks_file_1.rb
- path/to/hooks_file_2.rb
Hook File Format
Hook files are Ruby files that register hooks using the hooks.register method. Each hook receives a block that will be executed when the hook fires:
# Example: Log when mutations are inserted
hooks.register(:mutation_insert_pre) do |mutation:|
puts "About to insert mutation: #{mutation.identification}"
end
hooks.register(:mutation_insert_post) do |mutation:|
puts "Inserted mutation: #{mutation.identification}"
end
Common Use Cases
Rails Application with Database Isolation
Rails projects use these hooks to eager-load the application (so subjects are discoverable) and to give each parallel worker its own database. The full configuration — including the recommended env_infection_post eager-load hook and PostgreSQL and SQLite per-worker isolation examples — lives in Rails Integration.
Mutation Instrumentation
You can instrument mutations for logging, tracing, or debugging:
hooks.register(:mutation_insert_pre) do |mutation:|
# Log mutation details to a file
File.open('mutation_log.txt', 'a') do |f|
f.puts "#{Time.now}: Testing #{mutation.identification}"
end
end
Custom Test Environment Setup
Use integration hooks to configure your test environment:
hooks.register(:setup_integration_pre) do
# Perform custom setup before test framework is initialized
load_custom_helpers
configure_test_environment
end
hooks.register(:setup_integration_post) do
# Verify test framework is properly configured
validate_test_configuration
end
Environment Infection Customization
Customize how your application loads:
hooks.register(:env_infection_pre) do |env:|
# Set up special loading requirements
require 'custom_loader'
end
hooks.register(:env_infection_post) do |env:|
# Verify environment is properly loaded
validate_application_state
end
Hook Execution Order
When multiple hooks are registered for the same event:
- Hooks from files are loaded in the order specified in the configuration
- Within each file, hooks are registered in the order they appear
- All hooks for an event execute sequentially in registration order
Example:
# In first_hooks.rb
hooks.register(:mutation_insert_pre) do |mutation:|
puts "First hook"
end
# In second_hooks.rb
hooks.register(:mutation_insert_pre) do |mutation:|
puts "Second hook"
end
With configuration:
hooks:
- first_hooks.rb
- second_hooks.rb
Output when mutation is inserted:
First hook
Second hook
Implementation Details
- Hooks are implemented in
lib/mutant/hooks.rb - The
Mutant::Hooks::Builderclass is used during hook file evaluation - All hook data structures are immutable (frozen) after creation
- Hook files are evaluated using
binding.eval()with the builder as context - Unknown hook names raise
Mutant::Hooks::UnknownHookerror
Error Handling
Specifying an invalid hook name will raise an error:
hooks.register(:invalid_hook_name) do
# This will raise: Mutant::Hooks::UnknownHook: Unknown hook :invalid_hook_name
end
Valid hook names are limited to the 8 hooks listed at the top of this document.
Notes
- Hook blocks should be idempotent when possible
- Avoid long-running operations in hooks as they will slow down mutation testing
- Worker process hooks run in isolated child processes
- Environment and integration hooks run in the main process
- Mutation hooks run for each mutation being tested