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
muttest
as dev-dependency for your crate - Annotate your code (e.g.
impl
blocks) 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.json
contains the report in json format.
If you want to include the integration tests in mutation analysis, the setup needs to be a bit different:
muttest
is an optionaldependency
instead of adev-dependency
.- The attributes are guarded with
#[cfg_attr(feature = "muttest", ...)]
- Run
cargo muttest
without--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 fn
s, 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 = true
In 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-codegen
in directorycodegen
muttest
in directoryapi
re-exports the relevant types from the proc-macro crate and the core cratemuttest-selftest
in the directoryselftest
for mutation testing ofmuttest
itself.
- 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.