Tutorial - improving code coverage

Introduction

Diffblue Cover is designed to get good coverage “out of the box” without needing any configuration. That said, the amount of coverage you get is also dependent on the testability of your code, the build configuration of the project, and also the specific domain or environment that your code operates within. In this section we’ll give you several ways to increase your code coverage.

Completely compile your project

This might sound obvious, but sometimes getting a complete compilation of a project can be a high bar! If the project is not completely compiled, Cover won’t be able to write a full set of tests because it works on compiled bytecode.

Run the command to build the entire project, which is typically something like mvn install -DskipTests - the docs for the project should tell you. See Compiling your project successfully for further troubleshooting.

IntelliJ-specific compilation advice

If you're using IntelliJ, note that sometimes it isn’t obvious that the project didn’t completely compile due to the interaction between IntelliJ and the underlying build system. Compiling the project externally by running a Maven command from the command line or a run configuration is not sufficient.

IntelliJ needs to import the build configuration which can be achieved by selecting Maven or Gradle from the right side bar and clicking the Reload All Projects button (two circular arrows symbol). The project must compile correctly using the Build Project button (green hammer symbol).

Fix missing/broken dependencies

Diffblue Cover works by running your code, and so it needs all the dependencies to be correct. Crucially, it requires the dependencies listed in the build system to match the actual dependencies in the code. In our experience, it's common to see discrepancies between the POM file (Maven) dependencies and the code due to the complexity of dependency management and Java’s dynamic class loading.

If your project is fully compiled and you are seeing class loading errors in the output of Cover, it’s usually a sign there’s a missing dependency, or an incorrect version of a dependency.

  • Code that is deployed on an application server such as Tomcat may make use of provided-scope dependencies. Such dependencies are assumed to be provided by the application server, but Cover does not have access to these dependencies.

  • Dependencies-of-dependencies can also be a problem: they are not required for building the project because none of their classes are directly referenced, but they are required for running your code because they are referenced from a class in your dependencies. For example, interfaces and implementations are often packaged separately; whereas your code compiles with just the interface (often called api) dependency, it does not execute without having the dependency containing the interface implementations on the classpath too. Similarly, mock implementations of the API required for unit testing may be packaged separately and need to be added to test scope.

In either situation, you have to make sure that these dependencies are indeed part of the compile and test classpaths. Cover outputs the classpath that it receives from Maven or Gradle in its log file. If required dependencies are missing there, then change the scope of these dependencies in the build system configuration.

Allocate more memory / CPU

Cover requires at least 8GB of memory and 2 cores to function, but the more memory and CPU you can give it, the faster it goes. When we are conducting a search for the best test, a slow machine can result in the search timing out, producing fewer tests.

Ensure that sufficient memory is available to Cover. By default, the JVM only allocates a quarter of your physical memory to Java programs. That is 2GB if you have 8GB of RAM and 4GB if you have 16GB etc. 2GB is sufficient in most situations; on some projects you may need 4GB. If you want to give Cover more memory than the JVM default then you must change the JVM settings to increase the amount of RAM available to Java. See Memory management for further troubleshooting information.

You may also see warnings when your machine is heavily loaded, e.g. because you have multiple applications running that take up most of the cores of your machines (browser, video conferencing, IDE, compilation). In such cases, there is not enough CPU available to run Cover and it will slow down too much to operate properly. You have to reduce the load on your machine or make additional cores/memory available to Cover. If you are running Cover inside a VM or a container, change the settings to allocate more vCPUs and/or more memory to the VM and restart.

Disable the sandbox

By default, Cover runs with the Java sandbox turned on because we do not want to damage your system environment by wiping your filesystem, sending sensitive data on the network, or deleting your database. Also, if that code writes to the file system or does network IO then we run the risk of non-deterministic behavior. We try to mock out this kind of IO, but there are situations where we can’t.

The net: disabling the sandbox when you're running in a safe environment could allow Diffblue Cover to get more coverage for this code, and then you can look at refining mocking controls and other behavior.

Use the --disable-sandbox argument to disable the Diffblue sandbox - see Diffblue Sandbox and Commands & Arguments for details.

Custom strings / inputs

Tell Diffblue Cover about custom strings / inputs that your code expects to see. Cover is pretty smart about constructing inputs to methods, using a variety of techniques and heuristics. But when there are highly specific formatting requirements (especially for strings) and no examples of such strings in the code, Cover will not be able to find a correctly formatted input.

In these situations you can give Cover hints using the DiffblueRules YAML file. In the XXL-JOB open source project, for example, crucial methods require a cronExpression – a string that is in UNIX cron syntax. There are ~100 lines of comments that explain the formatting requirements!

To tell Cover what to do in this specific situation, you can create a DiffblueRules.yml file in the root of the module containing the following:

java.lang.String:
- immediate: "0 0 14-6 ? * FRI-MON"
- parameter: cronExpr

Whenever Cover needs to create a cronExpression parameter, it will use the string above. This hint allows Cover to create an additional 140 tests in that class.

You can tell Cover about any basic type and also use RegEx matching rules to tell Cover where to use them.

See Customizing test inputs for more details.

Last updated