Knowledge Base > Troubleshooting > Working with code R015

Working with code R015

If you receive the output code R015, this means the method under test performs operations which produce results that cannot be reproduced in a deterministic way, e.g. methods calling a random number generator, or that rely on the current timestamp.

While our policy is not to test methods that contain operations producing results that cannot be reproduced in a deterministic way, we suggest checking if the method also contains business logic that needs to be verified. If that’s the case, in order to have tests for the business logic, and consequently increase line coverage, refactor your code so that any deterministic logic is contained in a separate, unit-testable method.

Example:

The following piece of code formats a message to be displayed:

1.  public class MessageFormatter {
2.    DateTimeFormatter formatter =
        DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
3.
4.    public String formatMessage (String username, String message) {
5.      // username
6.      String userHandle = username.trim();
7.      if (!userHandle.startsWith("@")) {
8.        userHandle = "@"+userHandle;
9.      }
10.
11.    // timestamp
12.    String timestamp = LocalDateTime.now().format(formatter);
13.
14.    // message
15.    String escapedMessage = HtmlUtils.htmlEscape(message.trim());
16.
17.    return String.format("%s %s: %s", userHandle, timestamp, escapedMessage);
18.   }
19. }
 
 

We can see at line 12 that the method formatMessage uses LocalDateTime.now() to add the timestamp to the formatted message. This would cause unit tests to produce a different formatted message depending on the date and time of execution.

We could refactor the code so that the non-deterministic code, in this case LocalDateTime.now() is executed separately, leaving the rest of the business logic in a testable method, as follows:

1.  public class MessageFormatter {
2.    DateTimeFormatter formatter =
        DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
3.
4.    public String formatMessage (String username, String message) {
5.      return formatMessage(username, LocalDateTime.now(), message);
6.    }
7.
8.    String formatMessage (String username, LocalDateTime
9.        messageTimestamp, String message) {
10.     // username
11.     String userHandle = username.trim();
12.     if (!userHandle.startsWith("@")) {
13.       userHandle = "@"+userHandle;
14.     }
15.
16.     // timestamp
17.     String timestamp = messageTimestamp.format(formatter);
18.
19.     // message
20.     String escapedMessage = HtmlUtils.htmlEscape(message.trim());
21.
22.     return String.format("%s %s: %s", userHandle, timestamp, escapedMessage);
23.   }
24. }

Now, Diffblue Cover is able to write tests for formatMessage, and provide coverage for lines 10-21. Here’s an example of the test created:

1.  @Test
2.  public void testFormatMessage() {
3.    // Arrange
4.    MessageFormatter messageFormatter = new MessageFormatter();
5.
6.    // Act and Assert
7.    assertEquals("@janedoe 1 Jan 1, 01:01:00: Not all who wander are lost",
8.      messageFormatter.formatMessage("janedoe",
9.         LocalDateTime.of(1, 1, 1, 1, 1), "Not all who wander are lost"));
10. }