In this topic we show both the input source code, and the tests written by Diffblue Cover, for code of varied complexity, accompanied by a detailed narrative to help you further understand tests created by Diffblue Cover.
Basic assertions
This is a simple example of Spring Service source code with a trivial getter. Cover can write a Spring Boot test for the getter in a service provider by inlining Arrange, Act, and Assert.
Source
import org.springframework.stereotype.Service;
@Service
public class SimpleService
{
public String getValue() {
return "a really simple service";
}
}
Test written by Diffblue Cover
@SpringBootTest
@RunWith(org.springframework.test.context.junit4.SpringRunner.class)
public class SimpleServiceDiffblueTest {
@Autowired
private SimpleService simpleService;
@Test
public void diffbluetestGetValue() {
// Arrange, Act and Assert
assertEquals("a really simple service", this.simpleService.getValue());
}
}
Mocking
This is a class that contains two methods to upload and download a file to/from an Amazon S3 bucket. As the Amazon S3 bucket is a cloud storage mechanism, the test for this class/methods requires dependency injection. Cover can mock these types of dependencies and tests the downloadFileFromBucket method by asserting the expected S3Object and the downloaded S3Object using the method.
Source
@Service
public class AmazonService {
@Autowired
private AmazonS3 s3client;
public PutObjectResult uploadFileToBucket(String bucketName, String key, File file) {
return s3client.putObject(bucketName, key, file);
}
public S3Object downloadFileFromBucket(String bucketName, String key) {
return s3client.getObject(bucketName, key);
}
}
Tests written by Diffblue Cover
@SpringBootTest
public class AmazonServiceDiffblueTest {
@MockBean
private AmazonS3Client amazonS3Client;
@Autowired
private AmazonService amazonService;
@Test
public void diffbluetestUploadFileToBucket() {
// Arrange
PutObjectResult putObjectResult = new PutObjectResult();
putObjectResult.setContentMd5("file-hash");
when(this.amazonS3Client.putObject(or(isA(String.class), isNull()), or(isA(String.class), isNull()),
or(isA(File.class), isNull()))).thenReturn(putObjectResult);
// Act and Assert
assertSame(putObjectResult, this.amazonService.uploadFileToBucket("foo", "foo",
Paths.get(System.getProperty("java.io.tmpdir"), "test.txt").toFile()));
}
@Test
public void diffbluetestDownloadFileFromBucket() throws UnsupportedEncodingException {
// Arrange
StringInputStream objectContent = new StringInputStream("file-name");
S3Object s3Object = new S3Object();
s3Object.setObjectContent(objectContent);
when(this.amazonS3Client.getObject(or(isA(String.class), isNull()), or(isA(String.class), isNull())))
.thenReturn(s3Object);
// Act and Assert
assertSame(s3Object, this.amazonService.downloadFileFromBucket("foo", "foo"));
}
}
OS agnostic assertions
This example returns time in a different format. Cover writes a test to assert date and time that is not dependent on operating system or local time zones.
Source
public class TimeInAliceWonderland {
private static final String DODO_DATETIME_FORMAT = "ss:mm:HH dd-MMM-yyyy";
public static String reformatDodoDateTime(Date humanDate) {
Map<String, DateFormat> dateFormatMap = new HashMap<>();
dateFormatMap.put(DODO_DATETIME_FORMAT, new SimpleDateFormat(DODO_DATETIME_FORMAT));
return dateFormatMap.get(DODO_DATETIME_FORMAT).format(humanDate);
}
}
In this example, Cover writes two tests to cover each pathway through the conditional - a test which adds 10 to the balance and asserts the new balance should be 20 and a second test where the account is closed.
Source
public class Account {
private final long accountNumber;
private final Client client;
private long currentBalance;
private String accountName;
private AccountState accountState;
public Account(final long accountNumber, final Client client, final long amount) {
this.accountNumber = accountNumber;
this.client = client;
currentBalance = amount;
accountName = "Current";
accountState = AccountState.OPEN;
}
public long getCurrentBalance() {
return currentBalance;
}
public void addToBalance(final long amount) throws AccountException {
if (getAccountState() != AccountState.OPEN) {
throw new AccountException("Cannot add to balance, account is closed.");
}
currentBalance += amount;
}
Test written by Diffblue Cover
@Test
public void diffbluetestAddToBalance() throws AccountException {
// Arrange
Account account = new Account(1234567890L, new Client("Carlos Welch"), 10L);
// Act
account.addToBalance(10L);
// Assert
assertEquals(20L, account.getCurrentBalance());
}
Example of complex logic
This example code has three branches - Cover covers 100% of branches and creates three tests for three cases using existing enum values.
Source
public class VirtualSnackCupboard {
public static Snack whatCanISnackNow(int oClock) {
if (oClock == 10) {
return Snack.CHOCOLATE;
} else if (oClock == 15) {
return Snack.CAKES;
} else {
return Snack.VEGGIE;
}
}
enum Snack {VEGGIE, CHOCOLATE, CAKES}
}
Diffblue Cover CLI deliberately does not test trivial methods such as getters, setters, constructors and factory methods to avoid creating large quantities of noisy tests that do not contribute to overall coverage. There isn't a benefit to be gained from testing these trivial methods directly as, for example, getters and setters simply access attributes so there is no actual logic to be tested. Similarly, constructors and factory methods also contain little or no logic. If Diffblue Cover CLI did test such methods directly, a minor coverage increase might be gained, but this "improvement" would be meaningless in terms of improving code quality.
Ultimately these trivial methods will be covered when Cover generates tests for other methods that call these trivial methods. Diffblue recommends improving the percentage of coverage using the many options within the product, as shown in the Commands & Arguments topic.