gradle-pitest-plugin

Gradle plugin for PIT Mutation Testing


Project maintained by szpak Hosted on GitHub Pages — Theme by mattgraham

Gradle plugin for PIT Mutation Testing

The plugin provides an ability to perform a mutation testing and calculate a mutation coverage of a Gradle-based projects with PIT.

Maven Central Build Status Travis Build Status Jenkins

Quick start

Generic approach

Add gradle-pitest-plugin to the buildscript dependencies in your build.gradle file:

buildscript {
    repositories {
        mavenCentral()
        //Needed only for SNAPSHOT versions
        //maven { url "http://oss.sonatype.org/content/repositories/snapshots/" }
    }
    dependencies {
        classpath 'info.solidsoft.gradle.pitest:gradle-pitest-plugin:1.1.9'
    }
}

Apply the plugin:

apply plugin: "info.solidsoft.pitest"

Call Gradle with pitest task:

gradle pitest

After the measurements a report created by PIT will be placed in ${PROJECT_DIR}/build/reports/pitest directory.

Older gradle-pitest-plugin versions (<1.1.0)

For versions <1.1.0 the plugin can be applied with:

apply plugin: "pitest"

New plugin mechanism introduced in Gradle 2.1

The plugin upload mechanism to Gradle Plugins Repository has changed once again and gradle-pitest-plugin 1.1.6+ artifacts are available only from Maven Central.

Plugin configuration

The Pitest plugin has to be configured. All the command line options are supported. To make life easier taskClasspath, mutableCodePaths, sourceDirs, reportDir and pitestVersion are automatically set by a plugin. In addition sourceDirs, reportDir and pitestVersion can be overridden by an user.

In the past there was one mandatory parameter - targetClasses - which points to the classes which should be mutated. Starting from 0.32.0 it is only required if a group for the project is not set. Otherwise value "${project.group}.*" is set by default (which can be overridden using pitest.targetClasses parameter).

In case of using not default PIT version the pitestVersion parameter should be used to override it.

The configuration in Gradle is the real Groovy code which makes all assignments very intuitive. All values expected by PIT should be passed as a corresponding types. There is only one important difference. For the parameters where PIT expects a coma separated list of strings in a Gradle configuration a list of strings should be used (see outputFormats in the following example).

pitest {
    targetClasses = ['our.base.package.*']  //by default "${project.group}.*"
    pitestVersion = "1.1.0" //not needed when a default PIT version should be used
    threads = 4
    outputFormats = ['XML', 'HTML']
}

Check PIT documentation for a list of all available command line parameters. The expected parameter format in a plugin configuration can be taken from PitestPluginExtension.

There are a few parameters specific for Gradle plugin:

For example:

pitest {
    ...
    enableDefaultIncrementalAnalysis = true
    testSourceSets = [sourceSets.test, sourceSets.integrationTest]
    mainSourceSets = [sourceSets.main, sourceSets.additionalMain]
    jvmArgs = ['-Xmx1024m']
}

Multi-module projects support

gradle-pitest-plugin can be used in multi-module projects. The gradle-pitest-plugin dependency should be added to the buildscript configuration in the root project while the plugin has to be applied in all subprojects which should be processed with PIT. A sample snippet from build.gradle located for the root project:

//in root project configuration
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'info.solidsoft.gradle.pitest:gradle-pitest-plugin:1.1.9'
        (...)
    }
}

subprojects {
    ...
    apply plugin: 'info.solidsoft.pitest'   //'pitest' for plugin versions <1.1.0

    pitest {
        threads = 4

        if (project.name in ['module-without-any-test']) {
            failWhenNoMutations = false
        }
    }
}

Currently PIT does not provide an aggregated report for multi-module project. A report for each module has to be browsed separately. Alternatively a PIT plugin for Sonar can be used to get aggregated results.

Integration tests in separate subproject

Since gradle-pitest-plugin 1.1.4 it is possible to mutate code located in different subproject. Gradle internally does not rely on output directory from other subproject, but builds JAR and uses classes from it. For PIT those are two different sets of class files, so to make it work it is required to define both mainSourceSets and additionalMutableCodePaths. For example:

configure(project(':itest')) {
    apply plugin: "info.solidsoft.pitest"
    dependencies {
        compile project(':shared')
    }

    configurations { mutableCodeBase { transitive false } }
    dependencies { mutableCodeBase project(':shared') }
    pitest {
        mainSourceSets = [project.sourceSets.main, project(':shared').sourceSets.main]
        additionalMutableCodePaths = [configurations.mutableCodeBase.singleFile]
    }
}

The above is the way recommended by the Gradle team, but in specific cases the simpler solution should also work:

configure(project(':itest')) {
    apply plugin: "info.solidsoft.pitest"
    dependencies {
        compile project(':shared')
    }

    pitest {
        mainSourceSets = [project.sourceSets.main, project(':shared').sourceSets.main]
        additionalMutableCodePaths = project(':shared').jar.outputs.files.getFiles()
    }
}

Minimal working multi-project build is available in functional tests suite.

PIT plugins support

PIT plugins are officially supported since gradle-pitest-plugin 1.1.4 (although it was possible to use it since 1.1.0).

To enable PIT plugin it is enough to add it to pitest configuration in buildscript closure. For example:

buildscript {
   repositories {
       mavenCentral()
   }
   configurations.maybeCreate("pitest")
   dependencies {
       classpath 'info.solidsoft.gradle.pitest:gradle-pitest-plugin:1.1.9'
       pitest 'org.pitest.plugins:pitest-fancy-plugin:0.0.1'
   }
}

The minimal working example is available in functional tests suite.

Versions

Every gradle-pitest-plugin version by default uses a predefined PIT version. Usually this a the latest released version of PIT available at the time of releasing a plugin version. It can be overridden by using pitestVersion parameter in a pitest configuration closure.

Note. There could be some issues when using non default PIT versions.

gradle-pitest-plugin 1.1.x by default uses PIT 1.1.x, 1.0.x uses PIT 1.0.x, etc.

Note. Due to internal refactoring in PIT versions >=0.32 require gradle-pitest-plugin >=0.32.x and PIT versions <=0.31 gradle-pitest-plugin <=0.30.x.

Starting since version 1.1.6 gradle-pitest-plugin requires Gradle 2.0+ and was tested with Gradle 2.0 to 2.5 under OpenJDK 8, Oracle JDK 8 and OpenJDK 7. The latest version which supports older Gradle 1.x (1.6+) is gradle-pitest-plugin 1.1.4.

See changelog file for more detailed list of changes in the plugin itself.

FAQ

1. Why have I got java.lang.VerifyError: Expecting a stackmap frame... when using Java 7?

It should be fixed in PIT 0.29.
As a workaround in older versions add `jvmArgs = '-XX:-UseSplitVerifier'` to a pitest configuration block

    pitest {
        ...
        //jvmArgs = '-XX:-UseSplitVerifier'     //<0.33.0
        jvmArgs = ['-XX:-UseSplitVerifier']     //>=0.33.0
    }

2. Why have I got GroovyCastException: Cannot cast object '-Xmx1024', '-Xms512m' with class 'java.lang.String' to class 'java.util.List'

after upgrade to version 0.33.0?

To keep consistency with the new `mainProcessJvmArgs` configuration parameter and make an input format more predictable
`jvmArgs` parameter type was changed from `String` to `List<String>` in gradle-pitest-plugin 0.33.0. The migration is trivial,
but unfortunately I am not aware of the way to keep both parameter types active at the same time.

    pitest {
        ...
        //jvmArgs = '-Xmx1024 -Xms512m'     //old format
        jvmArgs = ['-Xmx1024', '-Xms512m']  //new format

    }

3. Why my Spring Boot application doesn't work correctly with gradle-pitest-plugin 0.33.0 applied?

Update. Spring Boot 1.1.0 is fully compatible with gradle-pitest-plugin.

There is was an issue with the way how spring-boot-gradle-plugin (<1.1.0) handles JavaExec tasks (including pitest task which in the version 0.33.0 became JavaExec task to resolve classpath issue with configured non default PIT version - see issue #7).

Luckily there is a workaround which allows to run PIT 0.33 (with Java 8 support) with gradle-pitest-plugin 0.32.0:

buildscript {
    (...)
    dependencies {
        classpath("info.solidsoft.gradle.pitest:gradle-pitest-plugin:0.32.0") {
          exclude group: "org.pitest"
        }
        classpath "org.pitest:pitest-command-line:0.33"
    }
}

pitest {
    pitestVersion = "0.33"
}

4. How can I override plugin configuration from command line/system properties?

Gradle does not provide a built-in way to override plugin configuration via command line, but gradle-override-plugin can be used to do that.

After applied gradle-override-plugin in your project it is possible to do following:

./gradlew pitest -Doverride.pitest.reportDir=build/pitReport -Doverride.pitest.threads=8

Note. The mechanism should work fine for String and numeric properties, but the are limitations with support of Lists/Sets/Maps and Boolean values.

For more information see project web page.

5. Why I see Could not find org.pitest:pitest-command-line:1.1.0 error in my multiproject build?

Could not resolve all dependencies for configuration ':pitest'.
> Could not find org.pitest:pitest-command-line:1.1.0.
  Required by:
      :Gradle-Pitest-Example:unspecified

Starting from version 1.0.0 for multi-project builds gradle-pitest-plugin dependency should be added to the buildscript configuration in the root project. The plugin should be applied in all subprojects which should be processed with PIT.

6. How can I change PIT version from default to just released the newest one?

gradle-pitest-plugin by default uses a corresponsing PIT version (with the same number). The plugin is released only if there are internal changes or there is a need to adjust to changes in newer PIT version. There is a dedicated mechanism to allow to use the latest PIT version (e.g, a bugfix release) or to downgrade PIT in case of detected issues. To override a defalt version it is enough to set pitestVersion property in the pitest configuration closure.

pitest {
    pitestVersion = "1.2.9-the.greatest.one"
}

In case of errors detected when the latest available version of the plugin is used with newer PIT version please raise an issue.

Known issues

Development

gradle-pitest-plugin cloned from the repository can be built using Gradle command:

./gradlew build

The easiest way to make a JAR with local changes visible in another project is to install it into the local Maven repository:

./gradlew install

There are also basic functional tests written using nebula-test which can be run with:

./gradlew funcTest

Support

gradle-pitest-plugin was written by Marcin ZajÄ…czkowski. The author can be contacted directly via email: mszpak ATT wp DOTT pl. There is also Marcin's blog available: Solid Soft - working code is not enough.

The plugin surely has some bugs and missing features. They can be reported using an issue tracker. However it is often a better idea to send a questions to the PIT mailing list first.

The plugin is licensed under the terms of the Apache License, Version 2.0.