Knowledge Base > Cover CLI > Customizing test setup
Customizing test setup
See also Customizing test inputs.
Background
A key feature of Diffblue Cover is automatically configuring classes such that the method under test can be successfully executed.
However, sometimes Diffblue Cover is unable to appropriately configure and clean up the environment such that tests can be usefully written and needs guidance from the user in the form of a custom base class which can provide behavior inherited by the test class.
Custom Base Class
When writing tests for com.example.SomeClass
Diffblue Cover will look for the existence of com.example.SomeClassDiffblueBase
and use that as a super-class when writing com.example.SomeClassDiffblueTest
.
This com.example.SomeClassDiffblueBase
class can contain methods to be run before/after writing tests, correctly annotated according to the testing framework used.
The base class needs to have the same name as the class under test, with a DiffblueBase
suffix appended, it must be in the same package as the class under test, but likely should be defined in the src/test/java
source tree so that it’s kept separate from production code.
Given a class under test: src/main/java/com/example/SomeClass.java
package com.example;
class SomeClass {
void methodUnderTest() {
// ...
}
}
and a custom base class: src/test/java/com/example/SomeClassDiffblueBase.java
package com.example;
class SomeClassDiffblueBase {
}
then Cover will write a test class src/test/java/com/example/SomeClassDiffblueTest.java
extending that custom base class.
package com.example;
import org.junit.jupiter.api.Test;
class SomeClassDiffblueTest extends SomeClassDiffblueBase {
@Test
void testMethodUnderTest() {
// Arrange
// ...
// Act
// ...
// Assert
// ...
}
}
Note: Once the custom base class has been written or updated, please make sure that it has been compiled so that Cover is able to find the compiled class.
@BeforeXXX
Annotated Methods
The most common use case for using a custom base class is to customize the test setup, often to perform some static initialization of some environmental state.
For example, your base class might need to switch to some test environment before tests are run at all, and might need to reset some license limits ahead of each test run.
If your class under test needs some shared environment state to be set up before tests are run at all, you can add a static, visible, no-argument method to your base class annotated with org.junit.jupiter.api.BeforeAll
(or org.junit.BeforeClass
if using JUnit 4) performing that initialization logic.
If your methods under test need some state setup or reset before each test is run, you can add a non-static, visible, no-argument method to your base class annotated with org.junit.jupiter.api.BeforeEach
(or org.junit.Before
if using JUnit 4) performing that initialization logic.
For example, your base class might look like the following, with setupTestEnvironment()
being called once before SomeClassDiffblueTest
, and resetLicenseLimits()
being called before each test method found:
package com.example;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
class SomeClassDiffblueBase {
@BeforeAll
static void setupTestEnvironment() {
// custom static configuration
Environment.state = new TestEnvironment();
}
@BeforeEach
void resetLicenseLimits() {
// reset license limits
Licensing.remainingUsages = 100;
}
}
@AfterXXX
Annotated Methods
A less common use case for a custom base class is to customize the test cleanup logic.
If your class under test needs some shared environment state to be cleared after tests are all run, you can add a static, visible, no-argument method to your base class annotated with org.junit.jupiter.api.AfterAll
(or org.junit.AfterClass
if using JUnit 4) performing that logic.
If your method under test needs some state reset after each test is run, you can add a non-static, visible, no-argument method to your base class annotated with org.junit.jupiter.api.AfterEach
(or org.junit.After
if using JUnit 4) performing that logic.
For example, your base class might look like the following, with resetLicenseUsageCount()
being called after each test in SomeClassDiffblueTest
and then resetTestEnvironment()
called after all the tests:
package com.example;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
class SomeClassDiffblueBase {
@AfterAll
static void resetTestEnvironment() {
// clear test configuration
Environment.state = null;
}
@AfterEach
void resetLicenseUsageCount() {
// reset license limits
Licensing.usageCount = 0;
}
}
Field Inputs
Another use case for custom base classes is to provide initialized inputs that Cover would otherwise struggle to get right.
For example, perhaps your method under test requires some ComplexObject
in order to execute, but it requires multiple calls to configure.
Note: Currently only static fields can be used.
Given a class under test: src/main/java/com/example/SomeClass.java
package com.example;
class SomeClass {
void methodUnderTest(ComplexObject complex) {
// ...
}
}
and a custom base class: src/test/java/com/example/SomeClassDiffblueBase.java
package com.example;
import org.junit.jupiter.api.BeforeEach;
class SomeClassDiffblueBase {
static ComplexObject complex;
@BeforeEach
void resetTestEnvironment() {
complex = ComplexObject.builder()
.withName("For Unit Tests")
.withSquareNumber(64)
.build();
}
}
Cover will use that initialized field to write the test class: src/test/java/com/example/SomeClassDiffblueTest.java
package com.example;
import org.junit.jupiter.api.Test;
class SomeClassDiffblueTest extends SomeClassDiffblueBase {
@Test
static void testMethodUnderTest() {
// Arrange
SomeClass someClass = new SomeClass();
// Act
someClass.methodUnderTest(SomeClassDiffblueBase.complex);
// Assert
// ...
}
}