mutant
Mutation testing for Ruby. AI writes your code. AI writes your tests. But who tests the tests?
Top Related Projects
minitest provides a complete suite of testing facilities supporting TDD, BDD, and benchmarking.
RSpec runner and formatters
Code coverage for Ruby with a powerful configuration library and automatic merging of coverage across test suites
A Ruby static code analyzer and formatter, based on the community Ruby style guide.
A library for setting up Ruby objects as test data.
Library for stubbing and setting expectations on HTTP requests in Ruby.
Quick Overview
Mutant is a mutation testing tool for Ruby. It helps developers improve their test suites by introducing small changes (mutations) to the source code and checking if the tests can detect these changes. This process helps identify weak spots in test coverage and encourages more robust test writing.
Pros
- Improves test suite quality and coverage
- Helps identify untested or poorly tested code paths
- Supports multiple Ruby versions and testing frameworks
- Provides detailed reports and metrics on mutation coverage
Cons
- Can be time-consuming for large codebases
- May produce false positives in certain scenarios
- Requires careful configuration to avoid excessive runtime
- Learning curve for interpreting and acting on mutation results
Code Examples
- Basic configuration in a Ruby project:
# Gemfile
gem 'mutant'
gem 'mutant-rspec'
# .mutant.yml
integration:
name: rspec
includes:
- lib
requires:
- my_project
- Running Mutant from the command line:
bundle exec mutant run --include lib --require my_project --use rspec 'MyProject*'
- Using Mutant with a specific Ruby file:
require 'mutant'
Mutant::CLI.run(['run', '--include', 'lib', '--require', 'my_project', 'MyProject::SpecificClass'])
Getting Started
-
Add Mutant to your Gemfile:
gem 'mutant' gem 'mutant-rspec' # or mutant-minitest, depending on your test framework -
Create a
.mutant.ymlconfiguration file in your project root:integration: name: rspec includes: - lib requires: - your_project_name -
Run Mutant from the command line:
bundle exec mutant run 'YourProject*' -
Analyze the output and improve your tests based on the mutation results.
Competitor Comparisons
minitest provides a complete suite of testing facilities supporting TDD, BDD, and benchmarking.
Pros of Minitest
- Lightweight and fast, with minimal setup required
- Built-in support for Ruby's standard library
- Simple and intuitive syntax for writing tests
Cons of Minitest
- Limited mutation testing capabilities
- Less comprehensive code coverage analysis
- Fewer advanced features for complex testing scenarios
Code Comparison
Minitest example:
require 'minitest/autorun'
class TestExample < Minitest::Test
def test_addition
assert_equal 4, 2 + 2
end
end
Mutant example:
class Calculator
def add(a, b)
a + b
end
end
Mutant::CLI.run(['--include', 'lib', '--require', 'calculator', 'Calculator#add'])
Mutant focuses on mutation testing, automatically generating and testing code mutations to ensure thorough test coverage. Minitest, on the other hand, provides a simpler framework for writing and running tests without built-in mutation testing capabilities.
Mutant offers more advanced features for detecting edge cases and improving test quality, while Minitest excels in simplicity and ease of use for basic testing needs. The choice between the two depends on the project's complexity and testing requirements.
RSpec runner and formatters
Pros of RSpec-Core
- Widely adopted and well-established testing framework for Ruby
- Extensive documentation and community support
- Intuitive, expressive syntax for writing tests
Cons of RSpec-Core
- Slower test execution compared to Mutant
- Limited built-in mutation testing capabilities
- Requires additional setup for advanced testing scenarios
Code Comparison
RSpec-Core example:
describe Calculator do
it "adds two numbers" do
calc = Calculator.new
expect(calc.add(2, 3)).to eq(5)
end
end
Mutant example:
class Calculator
def add(a, b)
a + b
end
end
Mutant::CLI.run(%w[--include lib --require calculator Calculator])
RSpec-Core focuses on behavior-driven development (BDD) and provides a readable syntax for writing tests. It's widely used in the Ruby community and offers extensive documentation and plugins.
Mutant, on the other hand, is a mutation testing tool that automatically modifies your code to ensure your tests catch all possible edge cases. It's more focused on code coverage and finding potential bugs that traditional testing might miss.
While RSpec-Core is easier to get started with and has a larger ecosystem, Mutant offers more advanced testing capabilities, particularly in identifying untested edge cases and improving overall code quality.
Code coverage for Ruby with a powerful configuration library and automatic merging of coverage across test suites
Pros of SimpleCov
- Easier to set up and use, with minimal configuration required
- Provides clear, HTML-based reports for code coverage
- Integrates well with various Ruby testing frameworks
Cons of SimpleCov
- Limited to code coverage analysis, lacking advanced mutation testing features
- May not catch logical errors or ineffective tests as effectively as mutation testing
- Can sometimes produce false positives in coverage reports
Code Comparison
SimpleCov setup:
require 'simplecov'
SimpleCov.start
# Your tests go here
Mutant setup:
require 'mutant'
Mutant::CLI.run(%w[
--include lib
--require my_project
--use rspec
MyProject*
])
Key Differences
- SimpleCov focuses on code coverage, while Mutant performs mutation testing
- Mutant provides more in-depth analysis of test effectiveness
- SimpleCov generates user-friendly HTML reports, whereas Mutant outputs detailed console results
- Mutant requires more setup and configuration compared to SimpleCov
- SimpleCov is generally faster to run, while Mutant's analysis is more time-consuming but potentially more thorough
Both tools serve different purposes in the testing ecosystem, with SimpleCov offering quick insights into code coverage and Mutant providing deeper analysis of test effectiveness through mutation testing.
A Ruby static code analyzer and formatter, based on the community Ruby style guide.
Pros of RuboCop
- Focuses on style and best practices enforcement
- Extensive configuration options for customization
- Large community and wide adoption in Ruby projects
Cons of RuboCop
- Can be overly opinionated, leading to false positives
- Performance can be slow on large codebases
- Limited to static code analysis, doesn't test runtime behavior
Code Comparison
Mutant example (mutation testing):
def add(a, b)
a + b
end
# Mutant might generate:
def add(a, b)
a - b
end
RuboCop example (style enforcement):
# Bad style
def some_method( x,y )
x+y
end
# RuboCop suggestion
def some_method(x, y)
x + y
end
Key Differences
- Mutant focuses on mutation testing to improve test coverage
- RuboCop emphasizes code style and best practices
- Mutant helps identify missing or weak tests
- RuboCop ensures consistent coding style across projects
Both tools serve different purposes in the Ruby ecosystem. Mutant is valuable for improving test quality, while RuboCop helps maintain consistent and clean code. Using both can significantly enhance Ruby project quality and maintainability.
A library for setting up Ruby objects as test data.
Pros of Factory Bot
- Widely adopted and well-established in the Ruby community
- Simplifies test data creation with a clean, intuitive API
- Extensive documentation and community support
Cons of Factory Bot
- Limited to test data generation, not a full mutation testing framework
- May encourage overuse of factories, leading to slower tests
Code Comparison
Factory Bot:
FactoryBot.define do
factory :user do
name { "John Doe" }
email { "john@example.com" }
end
end
Mutant:
class User
def initialize(name, email)
@name = name
@email = email
end
end
Key Differences
- Purpose: Factory Bot focuses on test data generation, while Mutant is a mutation testing tool
- Scope: Factory Bot is specific to testing, Mutant analyzes code quality and test coverage
- Usage: Factory Bot is used in test files, Mutant runs as a separate process to evaluate tests
When to Choose
- Use Factory Bot for creating test data and fixtures in Ruby projects
- Choose Mutant for improving test quality and identifying untested code paths
Both tools serve different purposes in the Ruby ecosystem and can be used complementarily in a project to enhance testing and code quality.
Library for stubbing and setting expectations on HTTP requests in Ruby.
Pros of WebMock
- Focused specifically on HTTP request stubbing and mocking
- Simpler setup and usage for web-related testing scenarios
- Extensive integration with popular HTTP libraries
Cons of WebMock
- Limited to HTTP mocking, less versatile for general-purpose testing
- May require additional tools for comprehensive test coverage
- Less emphasis on mutation testing and code quality improvement
Code Comparison
WebMock example:
stub_request(:get, "www.example.com").
to_return(status: 200, body: "stubbed response", headers: {})
Mutant example:
class Calculator
def add(a, b)
a + b
end
end
Mutant::CLI.run(['Calculator#add'])
Summary
WebMock is a specialized tool for HTTP request mocking, making it ideal for web-related testing scenarios. It offers simpler setup and usage for these specific cases. However, it's limited in scope compared to Mutant, which provides more comprehensive mutation testing and code quality analysis. WebMock focuses on verifying HTTP interactions, while Mutant aims to improve overall code quality by identifying potential bugs and edge cases through mutation testing.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
mutant
What is Mutant?
AI writes your code. AI writes your tests. But who tests the tests?
Copilot, Claude, and ChatGPT generate code faster than humans can review it. They'll even write tests that pass. But passing tests aren't the same as meaningful tests.
Mutant is mutation testing for Ruby. It systematically modifies your code and verifies your tests actually catch each change.
The more code AI writes for you, the more you need verification you can trust.
What is an Alive Mutation?
Each surviving (alive) mutation is a call to action with exactly one of two options:
- Keep the mutated code - your tests already specify the correct semantics, and the original code is redundant. Accept the mutation as a simplification.
- Add the missing test - the original code is correct, but the tests don't verify the behavior the mutation removed.
Author
Mutant was created and is developed by Markus Schirp. It is the subject of IEEE-published research and is included in the Trail of Bits Ruby Security Field Guide.
Quick Start
# lib/person.rb
class Person
def initialize(age:)
@age = age
end
def adult?
@age >= 18
end
end
# spec/person_spec.rb
RSpec.describe Person do
describe '#adult?' do
it 'returns true for age 19' do
expect(Person.new(age: 19).adult?).to be(true)
end
it 'returns false for age 17' do
expect(Person.new(age: 17).adult?).to be(false)
end
end
end
Tests pass. But run mutant:
gem install mutant-rspec
mutant run --use rspec --usage opensource --require ./lib/person 'Person#adult?'
Mutant finds a surviving mutation indicating a shallow test:
def adult?
- @age >= 18
+ @age > 18
end
Your tests don't cover age == 18. The mutation from >= to > doesn't break them.
This is just one of many mutation operators. Mutant also mutates arithmetic, logical, bitwise operators, removes statements, modifies return values, and more.
A full working example is available in the quick_start directory.
Session History
Mutant records every run to .mutant/results/. You can recall past results
without re-running mutation testing:
# List past sessions (most recent first)
mutant session list
# Show full report from the latest session
mutant session show
# Show full report from a specific session
mutant session show --session-id 019cf6f1-77e8-74b6-82db-f8b5faf570cd
# List subjects with alive/total mutation counts
mutant session subject
# Show alive mutations for a specific subject
mutant session subject 'Foo::Bar#baz'
# Remove old or incompatible session files
mutant session gc --keep 50
Next Steps
- Learn the nomenclature (subjects, mutations, operators)
- Set up your integration: RSpec or Minitest
- Run mutant on CI in incremental mode
Ruby Versions
Mutant is supported on Linux and macOS.
| Version | Runtime | Syntax | Mutations |
|---|---|---|---|
| 3.2 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| 3.3 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| 3.4 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| 4.0 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
Rails
Mutant runs against Rails applications, including parallel-worker database isolation (PostgreSQL and SQLite). The hook recipes are verified in CI on every non-EOL Rails version:
| Version | Status |
|---|---|
| 7.2 | :heavy_check_mark: |
| 8.0 | :heavy_check_mark: |
| 8.1 | :heavy_check_mark: |
See the Rails Integration guide for setup, eager loading, and per-worker database isolation. A runnable, CI-verified example lives in rails_example.
Licensing
Free for open source. Use --usage opensource for public repositories.
Commercial use requires a subscription ($30/month or $250/year per developer). Enterprise â reach out directly. See commercial licensing for pricing and details.
Documentation
- Configuration
- RSpec Integration
- Minitest Integration
- Rails Integration
- Incremental Mode
- Reading Reports
- Concurrency
- AST Pattern Matching
- Session JSON Schema
- Hooks
- Sorbet
- Nomenclature
- Limitations
- Mutant in the Wild
Communication
Contributing
See CONTRIBUTING.md for development setup and guidelines.
Acknowledgments
- Contributors
- The
mutant-minitestintegration was sponsored by Arkency
Top Related Projects
minitest provides a complete suite of testing facilities supporting TDD, BDD, and benchmarking.
RSpec runner and formatters
Code coverage for Ruby with a powerful configuration library and automatic merging of coverage across test suites
A Ruby static code analyzer and formatter, based on the community Ruby style guide.
A library for setting up Ruby objects as test data.
Library for stubbing and setting expectations on HTTP requests in Ruby.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot