SkillAgentSearch skills...

Ooze

🧬 Go Mutation Testing

Install / Use

/learn @gtramontina/Ooze

README

<h1 align="center"> <a href="https://github.com/gtramontina/ooze"> <img src=".assets/logo.svg" alt="ooze logo"> </a> </h1> <p align="center"> <a href="https://pkg.go.dev/github.com/gtramontina/ooze"><img src="https://pkg.go.dev/badge/github.com/gtramontina/ooze.svg" alt="Go Reference"></a> <a href="https://goreportcard.com/report/github.com/gtramontina/ooze"><img src="https://goreportcard.com/badge/github.com/gtramontina/ooze" alt="Go Report Card"></a> <a href="https://github.com/gtramontina/ooze/actions/workflows/ci.yml"><img src="https://github.com/gtramontina/ooze/actions/workflows/ci.yml/badge.svg" alt="CI Workflow"></a> <a href="https://github.com/gtramontina/ooze/actions/workflows/mutation.yml"><img src="https://github.com/gtramontina/ooze/actions/workflows/mutation.yml/badge.svg" alt="Mutation Testing Workflow"></a> </p>

Mutation Testing?

Mutation testing is a technique used to assess the quality and coverage of test suites. It involves introducing controlled changes to the code base, simulating common programming mistakes. These changes are, then, put to test against the test suites. A failing test suite is a good sign. It indicates that the tests are identifying mutations in the codeβ€”it "killed the mutant". If all tests pass, we have a surviving mutant. This highlights an area with weak coverage. It is an opportunity for improvement.

There are different types of changes that mutation tests can perform. A common collection usually include:

  • Changing an operator;
  • Replacing a constant;
  • Removing a statement;
  • Increasing/decreasing numbers;
  • Flipping booleans;

Mutations can also be domain/application-specific. Although, these are up to the maintainers of such application to develop.

It is worth mentioning that mutation tests can be quite expensive to run. Especially on larger code bases. And the reason is that for every mutation, on every source file, the entire suite of tests has to run. One can look at the bright side of this and think as an incentive to keep the test suites fast.

Mutation testing is a great ally in developing a robust code base and a reliable set of test suites.

Quick Start

Prerequisites

In order to ensure that you get accurate results, make sure that test suite that Ooze will run is passing. Otherwise, Ooze will report as if all mutants have been killed.

When Ooze reports that it found a living mutant, it will print a diff of the changes the virus made to the source file. The mutant source is printed using Go's go/format package. This means that, if your source code isn't gofmt'd, the diff may contain some formatting changes that are not relevant to the mutation. This isn't a prerequisite per se, but for a better experience, it is recommended that you run gofmt on your source files.

Installation

  1. Install ooze:

    go get github.com/gtramontina/ooze
    

    This pulls the latest version of Ooze and updates your go.mod and go.sum to reference this new dependency.

  2. Create a mutation_test.go file in the root of your repository and add the following:

    //go:build mutation
    
    package main_test
    
    import (
    	"testing"
    
    	"github.com/gtramontina/ooze"
    )
    
    func TestMutation(t *testing.T) {
    	ooze.Release(t)
    }
    

    The build tag is so you can better control when to run these tests (see the next step). This is a test as you'd write any other Go test. What differs is what the test actually does. And this is where it delegates to Ooze, by Releaseing it.

  3. Run with:

    go test -v -tags=mutation
    

    This will execute all tests in the current package including the sources tagged with mutation. This assumes that the above is the only test file in the root of your project. If you have other tests, you may want to put the mutation tests in a separate package, under ./mutation for example, and configure Ooze to use .. as the repository root (see WithRepositoryRoot below).

    If -v is enabled, Ooze will also be verbose. To enable Ooze's verbose mode only without the test framework verbosity, use -ooze.v.

    Note printing to stdout while Go tests are running has its intricacies. Running the tests at a particular package (without specifying which test file or subpackages, like ./...), allows for Ooze to print progress and reports as they happen. Otherwise, the output is buffered and printed at the end of the test run and, in some cases, only if a test fails. This is a limitation of Go's testing framework.

Results

Once all tests on all mutants have run, Ooze will print a report with the results. It will also exit with a non-zero exit code if the mutation score is below the minimum threshold (see WithMinimumThreshold below). This is an example of the report:

report sample

More examples of the results can be found in the mutation.yml workflow.

Settings

Ooze's Release method takes variadic Options, like so:

ooze.Release(
	t,
	ooze.WithRepositoryRoot("."),
	ooze.WithTestCommand("make test"),
	ooze.WithMinimumThreshold(0.75),
	ooze.Parallel(),
	ooze.IgnoreSourceFiles("^release\\.go$"),
)

The table below presents all available options.

| Option | Default | Description | |------------------------|---------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | WithRepositoryRoot | . | A string that configures which directory is the repository root. This is usually required when your mutation test file lives some other place that is not root itself. | | WithTestCommand | go test -count=1 ./... | The test command to run, as string. You may configure it as you wish, as a makefile phony target, for example. Or simply run the standard go test command with extra flags, such as timeout and tags. | | WithMinimumThreshold | 1.0 | A float between 0.0 and 1.0. This represents the minimum mutation test score to consider the execution successful. | | Parallel | false | Indicates whether to run the tests on the mutants in parallel. Given Ooze is executed via Go's testing framework, the level of parallelism can be configured when running the mutation tests from the command line. For example with go test -v -tags=mutation -parallel 3. | | IgnoreSourceFiles | nil | Regular expression representing source files to be filtered out and not suffer any mutations. | | WithViruses | all available (see below) | A list of viruses to infect the source files with. You can also implement your own viruses (generic or even application-specific). | | ForceColors | false | Forces colors in logs. This is useful when running the mutation tests in a CI environment, for example. |

Viruses

| Virus | Name | Description | |--------------------------------------------------------------------------------------------------|------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | arithmetic | Arithmetic | Replaces + with -, * with /, % with * and vice versa. | | arithmeticassignment | Arithmetic Assignment | Replaces +=, -=, *=, /=, %=, &=, <code>|=</code>, ^=, <<=, >>= and &^= with =. | | arithmeticassignmentinvert | Arithmetic Assignment Invert | Replaces += with `-=

View on GitHub
GitHub Stars279
CategoryDevelopment
Updated3d ago
Forks9

Languages

Go

Security Score

100/100

Audited on Apr 1, 2026

No findings