Search code examples
javajsongroovyjsonassert

JSONAssert - Compare within a specified range


I am comparing JSON responses from two different servers. They should basically match but due to caching, there are some small differences in fields such a temperature, wind speed, etc.

I am currently using a customization to ignore certain fields that always fail like this:

JSONAssert.assertEquals(response2.getResponseBodyContent(), response1.getResponseBodyContent(),
                        new CustomComparator(JSONCompareMode.LENIENT,
                        new Customization("**.TimeStamp", {a, b -> true}),
                        new Customization("**.EpochTime", {a, b -> true})
                        ));

Questions:

  1. How would I go about specifying a range (temperature can be within 10)?
  2. How to specify that the value only matches a certain type (string, integer)?

JSON Samples:

JSON 1

"Temperature":{
      "Metric":{
        "Value":4.6,
        "Unit":"C"
      },
      "Imperial":{
        "Value":40.0,
        "Unit":"F"
      }
    },
    "Wind":{
      "Direction":{
        "Degrees":293,
        "English":"WNW"
      },
      "Speed":{
        "Metric":{
          "Value":19.4,
          "Unit":"km/h"
        },
      "Imperial":{
          "Value":12.1,
          "Unit":"mi/h"
        }
      }

JSON 2

"Temperature":{
  "Metric":{
    "Value":5.1,
    "Unit":"C"
  },
  "Imperial":{
    "Value":43.0,
    "Unit":"F"
  }
},
"Wind":{
  "Direction":{
    "Degrees":271,
    "English":"ENE"
  },
  "Speed":{
    "Metric":{
      "Value":19.9,
      "Unit":"km/h"
    },
  "Imperial":{
      "Value":12.4,
      "Unit":"mi/h"
    }
  }

I am using a testing tool called Katalon which supports groovy/java. Any help would be greatly appreciated. Thanks!


Solution

  • I don't know Katalon, but I can take a good guess at how to fix this based on the code you've shown. This code:

    new Customization("**.TimeStamp", {a, b -> true})
    

    is providing a closure that compares any two TimeStamp nodes, passed as a and b, and always returns true. That effectively ignores TimeStamp (and EpochTime) in the comparison.

    To achieve what you want, you just need to supply a version of that closure that performs the check you want.

    To return true if the times are within ten seconds, you might do:

    new Customization("**.TimeStamp", {a, b -> Math.abs(a - b) < 10 })
    

    for example. You'll need to check the appropriate values for your data - TimeStamp is probably a text string that you'll need to parse into a suitable Date object first.

    The closure can have multiple lines of code, and can be defined separately:

    def fuzzyCompareTimeStamps = { a, b ->
        def dateA = new Date(a).parse(<whatever>)
        def dateB = new Date(b).parse(<whatever>)
        def absoluteDifference = Math.abs(dateA - dateB)
        return (absoluteDifference < 10)
    }
    
    new Customization("**.TimeStamp", fuzzyCompareTimeStamps)
    

    (This isn't tested code and won't work as written; it's just to give the flavour of how your solution will look).