• Stars
    star
    102
  • Rank 335,584 (Top 7 %)
  • Language
    Java
  • License
    Apache License 2.0
  • Created almost 9 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Assert that the java code of a project satisfies certain checks.

code-assert

Build Status codecov License Maven Central

Assert that the source code of a project satisfies certain rules.

Nobody follows rules that are not checked. If they are only checked periodically / manually by an "architect", it's often too late because there are already too many violations.
A better way is to define coding rules in JUnit tests. This way, they are asserted automatically and regularly. Violations of rules break the build and therefore, one is forced to either adjust the code to comply with the rules or to adapt the rules in a reasonable way.

code-assert supports rules on the package structure and the test coverage. It also integrates several static code analysis tools.

Language independent checks

Java checks

Kotlin checks

Other


Dependency

This is based on code from JDepend. It checks if the package structure contains cycles and/or follows the defined rules.

public class DependencyTest {

    // Analyze all sources in src/main/java
    private final AnalyzerConfig config = AnalyzerConfig.maven().main();

    @Test
    public void noCycles() {
        assertThat(new DependencyAnalyzer(config).analyze(), hasNoCycles());
    }

    @Test
    public void dependency() {
        // Defines the dependency rules for package org.proj
        class OrgProj extends DependencyRuler {
            // Rules for org.proj.dep, org.proj.model, org.proj.util
            DependencyRule dep, model, util;

            @Override
            public void defineRules() {
                base().mayUse(util, dep.allSubOf()); //org.proj may use org.proj.util and all subpackages of org.proj.dep
                dep.andAllSub().mustUse(model); //org.proj.dep and all subpackages thereof must use org.proj.model
                model.mayUse(util).mustNotUse(base()); //org.proj.model may use org.proj.util but not org.proj
            }
        }

        // All dependencies are forbidden, except the ones defined in OrgProj
        // java, org, net packages may be used freely
        DependencyRules rules = DependencyRules.denyAll()
                .withRelativeRules(new OrgProj())
                .withExternals("java.*", "org.*", "net.*");

        DependencyResult result = new DependencyAnalyzer(config).rules(rules).analyze();
        assertThat(result, matchesRulesExactly());
    }
}

Test coverage

Maven Central

To verify the test coverage of a project, JaCoCo can be used. The following steps are needed:

  • Add this to the <build><plugins> section of pom.xml:
<plugin>
    <groupId>guru.nidi</groupId>
    <artifactId>code-assert-maven-plugin</artifactId>
    <version>0.9.14</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare</goal>
                <goal>assert</goal>
            </goals>
        </execution>
    </executions>
</plugin>
  • prepare sets up the surefire plugin to run the tests with the JaCoCo agent which collects coverage data.
  • assert generates a coverage report and runs a coverage test (default is src/test/java/CodeCoverage.java, configurable through the testClass property).
  • Write a code coverage test:
public class CodeCoverage {
    @Test
    public void coverage() {
        // Coverage of branches must be at least 70%, lines 80% and methods 90%
        // This is checked globally and for all packages except for entities.
        JacocoAnalyzer analyzer = new JacocoAnalyzer(new CoverageCollector(BRANCH, LINE, METHOD)
                .just(For.global().setMinima(70, 80, 90))
                .just(For.allPackages().setMinima(70, 80, 90))
                .just(For.thePackage("org.proj.entity.*").setNoMinima()));
        assertThat(analyzer.analyze(), hasEnoughCoverage());
    }
}

FindBugs

Runs FindBugs on the code and finds questionable constructs.

public class FindBugsTest {
    @Test
    public void findBugs() {
        // Analyze all sources in src/main/java
        AnalyzerConfig config = AnalyzerConfig.maven().main();

        // Only treat bugs with rank < 17 and with NORMAL_PRIORITY or higher
        // Ignore the given bug types in the given classes / methods.
        BugCollector collector = new BugCollector().maxRank(17).minPriority(Priorities.NORMAL_PRIORITY)
                .just(In.everywhere().ignore("UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"))
                .because("It's checked and OK like this",
                        In.classes(DependencyRules.class, PmdRuleset.class).ignore("DP_DO_INSIDE_DO_PRIVILEGED"),
                        In.classes("*Test", "Rulesets")
                                .and(In.classes("ClassFileParser").withMethods("doParse"))
                                .ignore("URF_UNREAD_FIELD"));

        FindBugsResult result = new FindBugsAnalyzer(config, collector).analyze();
        assertThat(result, hasNoBugs());
    }
}

Checkstyle

Runs checkstyle on the code and finds questionable constructs.

public class CheckstyleTest {
    @Test
    public void checkstyle() {
        // Analyze all sources in src/main/java
        AnalyzerConfig config = AnalyzerConfig.maven().main();

        // Only treat issues with severity WARNING or higher
        StyleEventCollector collector = new StyleEventCollector().severity(SeverityLevel.WARNING)
                .just(In.everywhere().ignore("import.avoidStar", "javadoc.missing"))
                .because("in tests, long lines are ok", In.classes("*Test").ignore("maxLineLen"));

        //use google checks, but adjust max line length
        final StyleChecks checks = StyleChecks.google().maxLineLen(120);

        CheckstyleResult result = new CheckstyleAnalyzer(config, checks, collector).analyze();
        assertThat(result, hasNoCheckstyleIssues());
    }
}

PMD

Runs PMD on the code and finds questionable constructs and code duplications.

public class PmdTest {

    // Analyze all sources in src/main/java
    private final AnalyzerConfig config = AnalyzerConfig.maven().main();

    @Test
    public void pmd() {
        // Only treat violations with MEDIUM priority or higher
        // Ignore the given violations in the given classes / methods
        PmdViolationCollector collector = new PmdViolationCollector().minPriority(RulePriority.MEDIUM)
                .because("It's not severe and occurs very often",
                        In.everywhere().ignore("MethodArgumentCouldBeFinal"),
                        In.locs("JavaClassBuilder#from", "FindBugsMatchers").ignore("AvoidInstantiatingObjectsInLoops"))
                .because("it'a an enum",
                        In.classes("SignatureParser").ignore("SwitchStmtsShouldHaveDefault"))
                .just(In.classes("*Test").ignore("TooManyStaticImports"));

        // Define and configure the rule sets to be used
        PmdAnalyzer analyzer = new PmdAnalyzer(config, collector).withRulesets(
                basic(), braces(), design(), empty(), optimizations(),
                codesize().excessiveMethodLength(40).tooManyMethods(30));

        assertThat(analyzer.analyze(), hasNoPmdViolations());
    }

    @Test
    public void cpd() {
        // Ignore duplications in the given classes
        CpdMatchCollector collector = new CpdMatchCollector()
                .because("equals",
                        In.everywhere().ignore("public boolean equals(Object o) {"))
                .just(
                        In.classes(DependencyRule.class, Dependencies.class).ignoreAll(),
                        In.classes("SignatureParser").ignoreAll());

        // Only treat duplications with at least 20 tokens
        CpdAnalyzer analyzer = new CpdAnalyzer(config, 20, collector);

        assertThat(analyzer.analyze(), hasNoCodeDuplications());
    }
}

ktlint

Runs ktlint, a kotlin linter.

public class KtlintTest {
    @Test
    public void analyze() {
        // Analyze all sources in src/main/kotlin
        AnalyzerConfig config = AnalyzerConfig.maven(KOTLIN).main();

        KtlintCollector collector = new KtlintCollector()
                .just(In.classes("Linker").ignore("no-semi"));

        KtlintResult result = new KtlintAnalyzer(config, collector).analyze();

        assertThat(result, hasNoKtlintIssues());
    }
}

detekt

Runs detekt, a static code analysis tool for kotlin.

public class DetektTest {
    @Test
    public void analyze() {
        // Analyze all sources in src/main/kotlin
        AnalyzerConfig config = AnalyzerConfig.maven(KOTLIN).main();

        DetektCollector collector = new DetektCollector()
                .just(In.classes("Linker").ignore("MaxLineLength"));

        DetektResult result = new DetektAnalyzer(config, collector).analyze();

        assertThat(result, hasNoDetektIssues());
    }
}

Configuration reuse

Collector configurations can be defined separately and thus reused. Some configurations are defined in PredefConfig.

private final CollectorTemplate<Ignore> pmdTestCollector = CollectorTemplate.forA(PmdViolationCollector.class)
        .because("It's a test", In.classes("*Test")
                .ignore("JUnitSpelling", "AvoidDuplicateLiterals", "SignatureDeclareThrowsException"))
        .because("It's compiler generated code", In.languages(KOTLIN)
                .ignore("BC_BAD_CAST_TO_ABSTRACT_COLLECTION"));

@Test
public void pmd() {
    PmdViolationCollector collector = new PmdViolationCollector().minPriority(RulePriority.MEDIUM)
            .apply(pmdTestCollector)
            .because("It's not severe and occurs often", In.everywhere().ignore("MethodArgumentCouldBeFinal"));

    PmdAnalyzer analyzer = new PmdAnalyzer(config, collector).withRulesets(rules);
    assertThat(analyzer.analyze(), hasNoPmdViolations());
}

Standard tests

A test can inherit from CodeAssertTest. It should override one or more analyzeXXX methods. If it does so, these standard checks will be executed:

  • dependency rules
  • circular dependencies
  • PMD
  • PMD - unused actions
  • CPD
  • CPD - unused actions
  • FindBugs
  • FindBugs - unused actions
  • Checkstyle
  • Checkstyle - unused actions
//extend CodeAssertTest if you still use JUnit 4
public class CodeTest extends CodeAssertJunit5Test {

    private static final AnalyzerConfig CONFIG = AnalyzerConfig.maven().main();

    @Override
    protected DependencyResult analyzeDependencies() {
        class MyProject extends DependencyRuler {
            DependencyRule packages;

            @Override
            public void defineRules() {
                //TODO
            }
        }

        final DependencyRules rules = denyAll().withExternals("java.*").withRelativeRules(new MyProject());
        return new DependencyAnalyzer(CONFIG).rules(rules).analyze();
    }

    @Override
    protected FindBugsResult analyzeFindBugs() {
        final BugCollector bugCollector = new BugCollector().just(
                In.classes("*Exception").ignore("SE_BAD_FIELD"));
        return new FindBugsAnalyzer(CONFIG, bugCollector).analyze();
    }

    @Override
    protected CheckstyleResult analyzeCheckstyle() {
        final StyleEventCollector bugCollector = new StyleEventCollector().just(
                In.everywhere().ignore("javadoc.missing"));
        return new CheckstyleAnalyzer(CONFIG, StyleChecks.google(), bugCollector).analyze();
    }

    @Override
    protected PmdResult analyzePmd() {
        final PmdViolationCollector collector = new PmdViolationCollector().just(
                In.everywhere().ignore("MethodArgumentCouldBeFinal"));
        return new PmdAnalyzer(CONFIG, collector).withRulesets(basic(), braces()).analyze();
    }
}

More Repositories

1

graphviz-java

Use graphviz with pure java
Java
937
star
2

AngularJS-SpringMVC-example

Ein Beispielprojekt für das Zusammenspiel von AngularJS und Spring-MVC
JavaScript
74
star
3

raml-tester

Test if a request/response matches a given raml definition
Java
71
star
4

jekyll-image_optimizer

A jekyll plugin to optimize images for the web
Ruby
15
star
5

swiss-wowbagger

Let yourself be insulted in swiss german. Schöner fluchen auf Berndeutsch.
Kotlin
13
star
6

raml-tester-proxy

Test if requests/responses are raml compliant as a standalone proxy
Java
13
star
7

jwt-with-spring

Example project to show how to use JWT and Spring
Java
11
star
8

simple-3d

A simple CSG library to create models for 3D printing
Kotlin
7
star
9

ftp-sync

Java
5
star
10

emoji-art

Convert emojis into ascii art
JavaScript
5
star
11

raml-tester-js

4
star
12

js-border-layout

A simple border layout with CSS and JS
JavaScript
4
star
13

use-webjars-maven-plugin

use webjars as if they would be npm modules
Java
3
star
14

four-fours

Kotlin
2
star
15

java-universal-executable

Create a directly executable file (windows, linux and mac OS) from a java project.
Java
2
star
16

apikana-java

Maven plugin for apikana
Java
2
star
17

firetop

The classic top command using flames
Kotlin
1
star
18

dicamo

Kotlin
1
star
19

graphviz-taglet

Java
1
star
20

map-visualizer

Kotlin
1
star
21

graphviz-taglet9

Use graphviz in javadoc comments
Java
1
star
22

mbrola-jvm

A JVM wrapper around MBROLA diphone synthesizer
Kotlin
1
star
23

raml-tester-uc-servlet

Java
1
star
24

build-tools

Java
1
star
25

mariokart

1
star
26

astronomy

Some astronomy formulas
Kotlin
1
star
27

console-fun

Just a few utilities to help having fun with the console
Java
1
star
28

print3d

Kotlin
1
star
29

typescript-to-json-schema-extra

TypeScript
1
star
30

simple-remote-atlassian

Java
1
star
31

docker-latex

A complete latex system based on docker
JavaScript
1
star
32

jass

The swiss national card game
Kotlin
1
star
33

prok-sound

Experiments with generating raw waveforms
Kotlin
1
star
34

whatsapp-semi-bot

Java
1
star
35

d3-goodies-jvm

Some nice d3.js functions made usable for the JVM
Kotlin
1
star
36

big-banners

Create ASCII art banners
Kotlin
1
star
37

ngram

Kotlin
1
star
38

coarse

🐲 Convert an svg server-side with rough
JavaScript
1
star
39

project-euler

Solve problems of projecteuler.net
Python
1
star
40

raml-doc

Demo for a part of the GitHub API
Java
1
star