Are your tests any good?
Tests have one main purpose: to find bugs! How good are your tests at finding these?
We can simulate bugs by changing (mutating) the code. A good test suite should catch these bugs by failing, killing the mutant. A large number of surviving mutants hint at test suite defects.
- Install cargo plugin
cargo-muttest - Add
muttestas dev-dependency for your crate - Annotate your code (e.g.
implblocks) with#[cfg_attr(test, muttest::mutate)]. - Annotate the modules of your tests with
#[cfg_attr(test, muttest::tests)] - run
cargo muttest --lib - analyze the report. The file
target/muttest/report.jsoncontains the report in json format.
If you want to include the integration tests in mutation analysis, the setup needs to be a bit different:
muttestis an optionaldependencyinstead of adev-dependency.- The attributes are guarded with
#[cfg_attr(feature = "muttest", ...)] - Run
cargo muttestwithout--lib
Whatever setup you choose, make sure that muttest does not affect release-code.
Using the environment variable RUST_LOG=debug, you can see the commands executed during mutation analysis.
muttest can only mutate expressions that are executed at run-time.
It is not possible to mutate:
- const & static definitions
const fns, even when called at run-time- macros & their arguments
- patterns
- types
For technical reasons, only top-level items in modules can be annotated with #[mutate].
If the run-time of mutation analysis is dominated by mutant evaluation, you can instruct the compiler to optimize the test suite by adding this profile and adding the option --profile muttest when calling cargo muttest.
[profile.muttest]
inherits = "dev"
opt-level = 3
lto = trueIn a nutshell, the macro #[mutate] transforms certain patterns of source code and inserts hooks that can enable mutations at run-time.
This way, the code only needs to be compiled once.
Most of the functionality is implemented in the crate at the root of this repository, muttest-core.
The core library implements source code transformations, mutation activation, and code for program analysis.
This repository contains several other crates
muttest-codegenin directorycodegenmuttestin directoryapire-exports the relevant types from the proc-macro crate and the core cratemuttest-selftestin the directoryselftestfor mutation testing ofmuttestitself.
- Roland H. Untch, Andrew J. Offutt, and Mary J. Harrold: Mutation Analysis Using Mutant Schemata
- Mutant Schema Generation (MSG): using program transformation for mutation testing on Fortran programs
- llogiq:
mutagen- Using proc-macros for MSG in Rust
- Using dead branches to help the compiler with type inference (in this blog post)
- opportunistic mutations
- Autoderef-based specialization
- Autoref-based stable specialization by dtolnay
- Generalized Autoref-based specialization by Lukas introduces Autoderef-based specialization.