All Projects → nomisRev → AndroidQualityControl

nomisRev / AndroidQualityControl

Licence: other
Android Quality Control: PMD, Findbugs and Checkstyle. Gradle and Jenkins reports

Programming Languages

java
68154 projects - #9 most used programming language
kotlin
9241 projects

Android Quality Control

To increase and track the quality of your code there are serveral tools available. Aside from continuous integration (CI) tools like Jenkins and test coverage with Jacoco shown in Android Jacoco Gradle, there are some static code analysis tools out there like PMD, FindBugs and Checkstyle

Static code analysis

Static program analysis is the analysis of computer software that is performed without actually executing programs (analysis performed on executing programs is known as dynamic analysis). In most cases the analysis is performed on some version of the source code, and in the other cases, some form of the object code.

In other words, it is a tool that is going to analyse our code and point out bugs, mistakes, pitfalls. This is a tool and so it doens't work miracles!

You can expect it to point out unused code, redudant code, unchecked potetional NPE's etc

PMD

  • PMD is a source code analyser. That means it analyses your source code to find missing curly braces, redundant null check, long parameter list, unnecessary constructor, missing break in switch, etc. What it should report is configureable, more about this below.

  • PMD includes CPD (copy-paste-detector) which detects duplicated code.

  • Setting up PMD is relatively easy. The most important step here is to decide what you want PMD to check, and depending on these decisions you should setup your configuration.

  • The documentation can be rather tedious, and unhelpfull to setup the PMD configuration in gradle. This is a list of the possible Ruleset you can specify that PMD should analyse, the files linked here hold some documentation of what they do. More information can be found here PMD Rules. Don't forget that in Gradle, the rules must be prefixed with the language. So in our case the ruleset resides in the java folde. So prefix with java-

  • Combining these sources you should be able to figure out what configuration suits your project, and your setup might look something like this.

apply plugin: 'pmd'

check.dependsOn 'pmd'

task pmd(type: Pmd) {

    description "Generate PMD reports for this build"

    ignoreFailures true    // Ignores failing build on warning. If not set build will fail on warning.

    ruleSets = [
        "java-basic",
        "java-braces",
        "java-naming",
        "java-android",
        "java-codesize",
        "java-design",
        "java-finalizers",
        "java-junit",
        "java-optimizations",
        "java-strictexception",
        "java-strings",
        "java-unusedcode"
    ]

    source 'src'          // Specify the source code. The script should be applied to
    include '**/*.java'   // the module build.gradle so the 'src' folder resides at the same level
    exclude '**/gen/**'   // include / exclude folders and files.
    
    reports {
        xml.enabled = true
        html.enabled = true
    }
}

FindBugs

  • FindBugs is a bytecode analyser.FindBugs will thus analyse the compiled .class files.

  • FindBugs will search for common pitfalls in the compiled class files like infinite loops, reference comparison of Boolean values, equals() method fails on subtypes, clone method may return null, (32bit) int shifted by an amount not in the range (of 0-31), a collection which contains itself, equals method always returns true, etc.

  • FindBugs like PMD analyses your code and thus can be setup with a very minimal setup. FindBugs can also be configured with custom bugs, this setup is out of the scope of this article. More information on how to do this can be found here.

  • A basic setup might look something like this

apply plugin: 'findbugs'

check.dependsOn 'findbugs'

task findbugs(type: FindBugs) {

    description 'Generate FindBugs reports for this build'

    ignoreFailures true

    //Higher levels increase precision and find more bugs at the expense of running time and memory consumption.
    effort = 'max'
    //The priority threshold for reporting bugs. If set to {@code low}, all bugs are reported.
    reportLevel = 'low'

    //Define path to classes
    classes = fileTree("${project.rootDir}/app/build/intermediates/classes") //path to compiled class files
    
    source 'src'          // Specify the source code. The script should be applied to
    include '**/*.java'   // the module build.gradle so the 'src' folder resides at the same level
    exclude '**/gen/**'   // include / exclude folders and files.

    //Define exclude config file
    excludeFilter = file("${rootProject.projectDir}/gradle/config/findbugs/exclude.xml")

    //IMPORTANT: FINDBUGS CAN ONLY GENERATE 1 REPORT. XML OR HTML!! AND PATH MUST BE DEFINED!!
    reports {
        xml.enabled = false
        html.enabled = true
        xml.destination = "$project.buildDir/reports/findbugs/findbugs-output.xml"
        html.destination = "$project.buildDir/reports/findbugs/findbugs-output.html"
    }

    classpath = files()
}
  • A general exclude.xml file can be found in this repo. And it consists of a simple pattern to exclude files generated by the most common libraries like dagger, butterknife, kotlin, ... When using a library, you trust the developers code so this should not be included in the analysis

Since FindBugs analyses compiled class files it can be used with Kotlin (ノ◕ヮ◕)ノ*:・゚✧

Checkstyle

  • Checkstyle is a development tool to help programmers write Java code that adheres to a coding standard. Eventhough this might seem minor, adhering the same code style throughout a project can drastically increase readability and thus the quality of your code.

  • Checkstyle is something that takes a while to setup. You need to think about the codestyle you and the team you're in want to honor. And when setting deciding on codestyle conventions, it's easily to overlook certain situations. Luckily Checkstyle has a very good documentation, and it's highly configureable. For more information http://checkstyle.sourceforge.net/checks.html, an example of a config file can be found in this repo.

apply plugin: 'checkstyle'

check.dependsOn 'checkstyle'

task checkstyle(type: Checkstyle) {

    description "Generate Checkstyle reports for this build"     //Add description to task

    ignoreFailures true 

    configFile file("${rootProject.projectDir}/gradle/config/checkstyle/checkstyle.xml")

    source 'src'
    include '**/*.java'
    exclude '**/gen/**', '**/test/**'

    reports {
        xml.enabled = true
        html.enabled = true
    }

   classpath = files(file("${project.rootDir}/app/build/intermediates/classes"))
}

Source

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].