kotlinjunitkotlinx

How to compare actual and expected serialization result in kotlinx?


Note: I'm completely new to the Kotlin / JUnit ecosystem, so please bear with me if the question is missing something basic.

I'm working on a JSON-based file format. In the unit/integration tests, I'd like to check that the serialization produces exactly the same JSON tree as some reference JSON tree. In particular I'd like to make sure that the serialization handles subtleties like implicit or explicit nulls correctly.

I've added the expected JSON in form of a plain .json file as a test resource, so that I can now load the string content of the expected JSON. My issue is that I have test cases that require some rather deep/complex JSON trees, and I can't find a good way to get a meaningful test output if the comparison fails. Consider for instance the case that only a single value is wrong somewhere deep in the JSON tree. In Rust, I'm using for instance rust-pretty-assertions to solve these issues:

enter image description here

I've experimented with these approaches:

  1. Comparison based on JsonElement. I basically use:

     val actualContent: String = ... # from serialization
     val expectedContent: String = ... # from test fixture
     val actual = Json.parseToJsonElement(actualContent)
     val expected = Json.parseToJsonElement(expectedContent)
     Assertions.assertEquals(actual, expected)
    

    Unfortunately, if the comparison fails the test output just contains a line org.opentest4j.AssertionFailedError: expected: <{ ... long unformatted JSON ...}> which makes it very hard to spot the actual reason for the failed assertion. Of course this behavior makes sense, because if JsonElement.equals returns false, JUnit can do nothing more than print it.

  2. Direct string comparison: This is of course not perfect, because JSON-trees can be identical even if their string representation is different. However I was hoping that pretty-serializing them both would allow me to use some kind of string diff feature in JUnit. So far, I'm using JUnit's plain Assertions.assertEquals(actual, expected), which unfortunately just prints the two strings, saying they are not equal, without a hint where they differ.

Is there a feature either in kotlinx or JUnit that can produce an easy to interpret test failure output?

In case it matters: I'm using JUnit 5, but I'm open for alternatives.


Solution

  • I would recommend trying out JsonUnit. It will allow you to write assert for json with good messages on failure. An example using AssertJ integration:

    assertThatJson(actual).isEqualTo(expectedJson)
    

    ... that may produce the following output on an example similar to yours:

    Comparing expected:
    {"lorem":"Hello, Wrold!","ipsum":42,"dolor":{"value":"hey ho!"}}
    ------------
    with actual:
    {"lorem":"Hello, World!","ipsum":42,"dolor":{"value":"hey"}}
    
    Different value found in node "dolor.value", expected: <"hey ho!"> but was: <"hey">.
    Comparison Failure: 
    Expected :hey ho!
    Actual   :hey
    
    Different value found in node "lorem", expected: <"Hello, Wrold!"> but was: <"Hello, World!">.
    Comparison Failure: 
    Expected :Hello, Wrold!
    Actual   :Hello, World!
    

    It will add another dependency to your project, but it is only for test scope and it's well worth it...