Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I compare JSON in a grails test

Tags:

grails

groovy

I have a controller in Grails that is returning a response in JSON.

I have written a test which works roughly like this

test(){
     def expectedResponse=JSON.parse('[{"username":"user","startDate":"2010-11-30"}]')
    ...
            def actualResponse=JSON.parse(response.text)

            println "Expecting: ${expectedResponse.toString()}"
            println "Actual: ${actualResponse.toString()}"

            assertEquals(expectedResponse.toString(), actualResponse.toString())
    ...
        }

This works as expected

Expecting: [{"username":"user","startDate":"2010-11-30"}]
Actual: [{"username":"user","startDate":"2010-11-30"}]

However, I was wondering if there was a better way to do this without resorting to a string comparison.. Perhaps something that could leave me the flexibility to be able to add attributes to the response without invalidating my test case?

I could build this myself, but I would've expected some sort of JSON comparison to be built into the language.

Update: I tried doing this directly, without the toString and have had inconsistent results, not quite sure why, it was working at one stage then suddenly got this. I can't see any code changes I made that would've caused the difference

groovy.lang.MissingMethodException: No signature of method: com.siggysale.MainControllerTests.assertEquals() is applicable for argument types: (org.codehaus.groovy.grails.web.json.JSONArray, org.codehaus.groovy.grails.web.json.JSONArray) values: [[], []]
like image 673
Samuel Parsonage Avatar asked Mar 23 '23 08:03

Samuel Parsonage


2 Answers

You can compare json using GJSON libraray using the code below.

class GJsonUtil {

    static Boolean compareJsonStrings(String obj1, String obj2){
        JsonParser parser = new JsonParser();
        JsonElement o1 = parser.parse(obj1)
        JsonElement o2 = parser.parse(obj2)
        return o1==o2
    }
}

This is also tested using few test cases. As you can see order of element in a json doesn't matter i.e. {test1:1,test2:2} should be same as {test2:2,test1:1}.

class GJsonSpec extends UnitSpec {

    @Unroll("#ID : comparing two json")
    def "Comparing json string"() {

        setup:

        when:
        def json1String = (obj1 as JSON).toString()
        def json2String = (obj2 as JSON).toString()
        println "json1String=${json1String}"
        println "json2String=${json2String}"
        def match=GJsonUtil.compareJsonStrings(json1String,json2String)

        then:
             match==result

        where:

        ID | obj1                    | obj2                    | result
        1  | [a: 1, b: [c: 1, d: 2]] | [b: [c: 1, d: 2], a: 1] | true
        2  | [a: 1, b: [c: 1, d: 3]] | [b: [c: 1, d: 2], a: 1] | false
        3  | [a: 2, b: [c: 1, d: 2]] | [b: [c: 1, d: 2], a: 1] | false
        4  | [a: 1, b: [d: 1, c: 2]] | [b: [d: 1, c: 2], a: 1] | true
        5  | [a: 1, b: [d: [x:"ram",y:"Laxman"], c: 2]] | [b: [d: [x:"ram",y:"Laxman"], c: 2], a: 1] | true//deep json comparision
        6  | [a: 1, b: [d: [x:"Ram",y:"Laxman"], c: 2]] | [b: [d: [x:"ram",y:"laxman"], c: 2], a: 1] | false//deep json comparision+ lower/uppercase
        7  | [a: 1, b: [d: [x:"Ram",y:["test1","test2","test3"]], c: 2]] | [b: [d: [x:"Ram",y:["test1","test3","test2"]], c: 2], a: 1] | false//deep json comparision+ lower/uppercase
        8  | [a: ["test1","test2","test3"]] | [a:["test1","test2","test3"] ] | true//comaparing list order
        9  | [a: ["test1","test2","test3"]] | [a:["test1","test3","test2"] ] | false//comaparing list order should fail
        10|[:]|null|false
        11|null|[:]|false
        12|null|null|true
        13|[a: ["test1",null,"test3"]] | [a:["test1",null,"test3"] ] | true//comaparing nulls in json



    }


}

Hope that helps!!! Thanks,

Anuj Aneja

like image 100
Anuj Aneja Avatar answered Mar 24 '23 21:03

Anuj Aneja


How about comparing JSON values?

import groovy.json.JsonSlurper

def test() {
    def obj = new JsonSlurper().parseText(response.text)

    assert obj[0].username == "user"
    assert obj[0].startDate == "2010-11-30"

    // make sure there isn't any other data
    assert obj.size() == 1
    assert obj[0].size() == 2
}

(you have to use obj[0] instead of obj because you are returning a JSON array with 1 element)

like image 29
micha Avatar answered Mar 24 '23 22:03

micha