1

I have the following method. The method converts the contents of a json string by using the Jackson ObjectMapper. If the json is malformed the stack trace is printed and the object is set to null:

public ObjectTransferData extractJacksonObjectsFromFile(String json) {
  ObjectTransferData objectTransferData;
  try {
    objectTransferData = objectMapper.readValue(json, ObjectTransferData.class);
  } catch (Exception e) {
    e.printStackTrace();
    objectTransferData = null;
  }
  return objectTransferData;
}

I wrote the JUnit unit test for a possible malformed json string like this:

@Test
public void testExtractJacksonObjectsFromFile_malformedJson_expectNull(){
  String malformedJson = "{";
  ObjectTransferData result = myService.extractJacksonObjectsFromFile(malformedJson);
  assertNull(result);
}

This test passes. But it is also printing the e.printStackTrace() into my terminal which is obscuring the actual important logs during test execution. It can be confusing for the reader of the test execution.

I am wondering how to resolve this issue. I came up with these ideas:

  1. Remove the try/catch and just throw the exception. This would allow me to just write the test like this and not get a stacktrace into the console.
@Test
public void testExtractJacksonObjectsFromFile_malformedJson_expectException(){
  String malformedJson = "{";
  assertThrows(Exception.class, () ->
        objectImportService.extractJacksonObjectsFromFile(malformedJson)
  );
}

However the disadvantage is that the real application now throws this Exception and does not gracefully fail by handling it through a catch block.

  1. Somehow suppress the exception logging for the tests. But this could lead to supressed logs for actual errors during the test execution.

This question is somewhat related, but does not fully answer my question. I could just redirect all testing stacktraces to a file like this, but I don't want to redirect actual exceptions during test execution. Telling a specific test to not print stacktrace would be ideal.

Bishares
  • 67
  • 1
  • 13
  • This answer of [this](https://stackoverflow.com/a/9384651/12263454) thread just accepts these logs. But I am working with many colleagues who might get confused and think these are actual Exceptions. – Bishares Aug 26 '21 at 14:57
  • Use a logger, and configure the logger to not print as part of the test. Unrelated, but consider changing the return to an `Optional`. – Andrew S Aug 26 '21 at 15:01
  • I just read through the book Clean Code by Robert C. Martin again and found this piece of advice in the chapter about error handling: Don't write methods that return `null` if something went wrong. Instead throw an exception. So I will change my function to throw the exception. – Bishares Sep 07 '21 at 09:22

1 Answers1

1

You need to decide whether you want to change application behaviour (and report the exception as you already suggested) or to keep the behaviour and return a null.

But there is a third option, especially since you are after unit tests: Split the functionality of your method into two parts:

  1. the part that parses the JSON and throws an exception
  2. a wrapper function that catches the exception, prints it to stdout and returns null

Your unit test could now test 1) while the application uses 2).

If you do not like this either, you could - in your unit test - redirect stdout into some temporary ByteArrayStream before calling the exception throwing stuff, then not only check if null is returned but also if the byte array received the correct data.

Queeg
  • 7,748
  • 1
  • 16
  • 42