Defining Custom Units

Information is fed into the Diffblue Cover analysis engine in a specific order, and with specific classes grouped together. In some cases it can be more performant to tweak the structure of this ordering and grouping to yield more results more quickly. This information is referred to inside the platform as Units as strictly speaking it is Units of code that the platform will put under analysis. By default this is usually broken up by each Java module that is found in the project.

Where units are used

When running analysis on your project's code each function is analysed individually, but it is important any dependent code from other areas of your project are included. This could be other classes or static singleton utility classes that the function under analysis requires to perform its duty, or is maybe a custom class provided to it as a parameter. They're also used to determine the classes inside the project that the platform should analyse, which by default is all compiled code.

How units are found

Units can be defined inside the diffblue.yml file, under the parameter units. If not found, the analysis will first determine the units from the compiled classes after running your provided buildCmd. Example of diffblue.yml with units:

buildCmd: mvn compile
testCmd: mvn test
units:
  - target:
    - dir: target/classes
  #...

How units are structured

A unit is roughly analogous to a single JAR of bytecode that the analyser will use to calculate tests. This does not include any dependencies that the project has outside it's own source, as these are included in the class path. Therefore a unit should have as much interdependent code as possible, otherwise it runs the risk of mocking internal dependencies. The ordering of units is also important as the classes are analysed in the order that they are provided in the unit.

Example

#Array of 'Units'
- target:
  #Array of 'Targets'
  - dir: target/classes
    file: com/diffblue/javademo/Search.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/Search.java
  - dir: target/classes
    file: com/diffblue/javademo/TicTacToe.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/TicTacToe.java
  - dir: target/classes
    file: com/diffblue/javademo/UserAccess.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/UserAccess.java
  - dir: target/classes
    file: com/diffblue/javademo/nestedobjects/User.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/nestedobjects/User.java
  - dir: target/classes
    file: com/diffblue/javademo/nestedobjects/subpackage/Item.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/nestedobjects/subpackage/Item.java
  - dir: target/classes
    file: com/diffblue/javademo/nestedobjects/subpackage/Order.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/nestedobjects/subpackage/Order.java
  - dir: target/classes
    file: com/diffblue/javademo/serveraccess/DatabaseDao.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/serveraccess/DatabaseDao.java

This shows one single unit object and within that unit multiple targets. A target is a single compiled class file, with the dir and file which point to the class file for the target. The sourceDir and sourceFile then link to the original source .java file. Each parameter of the target is required for the platform to perform an analysis as the original source file is linked to the compiled class to provide line coverage information. In the above example all of the classes listed as a target will be compiled to the same jar file and will be provided to the analyser to analyse functions in each class file. So when analysing functions in User.java the analyser will also have access to the Order.java file. In the above file it might be that each class can be analysed in complete isolation, and we can change the yamlto look like this:

#Array of 'Units'
- target:
  #Array of 'Targets'
  - dir: target/classes
    file: com/diffblue/javademo/Search.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/Search.java
- target:
  #Array of 'Targets'
  - dir: target/classes
    file: com/diffblue/javademo/TicTacToe.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/TicTacToe.java
- target:
  #Array of 'Targets'
  - dir: target/classes
    file: com/diffblue/javademo/UserAccess.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/UserAccess.java
- target:
  #Array of 'Targets'
  - dir: target/classes
    file: com/diffblue/javademo/nestedobjects/User.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/nestedobjects/User.java
- target:
  #Array of 'Targets'
  - dir: target/classes
    file: com/diffblue/javademo/nestedobjects/subpackage/Item.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/nestedobjects/subpackage/Item.java
- target:
  #Array of 'Targets'
  - dir: target/classes
    file: com/diffblue/javademo/nestedobjects/subpackage/Order.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/nestedobjects/subpackage/Order.java
- target:
  #Array of 'Targets'
  - dir: target/classes
    file: com/diffblue/javademo/serveraccess/DatabaseDao.class
    sourceDir: src/main/java
    sourceFile: com/diffblue/javademo/serveraccess/DatabaseDao.java

You can also ensure that only a handful of classes are sent to the analyser, which can be useful if you have another form of coverage that you trust. Simply removing them from any target definition is enough to ensure that the class is not analysed.