Comparing JSON responses using JsonAssert Library - Lenient Mode

Automate Testing of Rest API using Rest Assured

Comparing JSON responses using JsonAssert Library - Lenient Mode

In one of the earlier post, we studied about Extracting a JSON Response with RestAssured, before following this tutorial, I would recommend reading the previous blogs .

I would assume that everyone following this tutorial has knowledge of Java and TestNG. If you need help then please follow tutorials on Java and TestNG .

In this post, we will learn about comparing JSON Responses using JSONAssert Library.

Once the response is extracted we will store it into Response class and later verify the entire response using a single assert statement instead of comparing specific attributes.

The disadvantage of directly comparing the response as string without JSONAssert is as follows:

  • If we compare two jsons by simply comparing the json string then it fails to let us know where exactly the comparison has failed. It will also mark json as failed if the order of array elements in json is different.

However if use JSONAssert Library, it will let us know the exact difference where the comparison between to json string has failed as well as not mark the test as failed if the order of array elements in an array is different if the comparator mode is lenient and if kept as strict then it mark test as failed if the order is different.

We will be using findplacefromtext Google Map API. Follow the create API Key Article for generating your key.

Now let's look at an example where we will search for a particular Railway Station in Mumbai City and then assert the expected response present in expectedResponse.txt file to the actual response using JsonAssert Library.

We will need to add following dependencies to the pom.xml of our maven project apart from the others mentioned in the earlier article

<dependencies>
  <dependency>
    <groupId>org.skyscreamer</groupId>
    <artifactId>jsonassert</artifactId>
    <version>1.5.0</version>
    <scope>test</scope>
  </dependency>
</dependencies>
import static io.restassured.RestAssured.basePath;
import static io.restassured.RestAssured.baseURI;
import static io.restassured.RestAssured.given;
import static java.nio.file.Files.readAllBytes;
import static java.nio.file.Paths.get;

import java.io.IOException;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.JSONCompareMode;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class JSONAssertTest {
  @BeforeClass
  public void setBaseUri() {

    baseURI   = "https://maps.googleapis.com";
    basePath  = "/maps/api/place/findplacefromtext/json";
  }

  @Test
  public void test01() throws IOException {
    var expectedResponse = new String(readAllBytes(get("src/test/java/expectedResponse.txt")));
    var actualResponse =
        given()
            .param("input", "Chhatrapati Shivaji Maharaj International Airport")
            .param("inputtype","textquery")
            .param("fields", "formatted_address,name,rating,opening_hours,geometry")
            .param("key", "xyz")
            .when()
            .get()
            .asString();
    JSONAssert.assertEquals(expectedResponse, actualResponse, JSONCompareMode.LENIENT);
  }
}

In setBaseUri method, we are simply setting the default URI to use in our tests and also setting the basePath of the API.

Now when we write out a test that calls an API (as we will do in the next step), we don’t have to type in the basePath in the get() call.

In test01 method, we are using the given - when - then format. We start with given method and specify input, inputtype, fields and key parameter using the param method then we use the when method and use the get method to call findplacefromtext API.

Remember that we set the defaults for the base URI and base path , so the full address of the API that is actually being called is as follows:

https://maps.googleapis.com/maps/api/place/findplacefromtext/json?input="Chhatrapati Shivaji Maharaj International Airport"&inputtype="textquery"&fields="formatted_address,name,rating,opening_hours,geometry"&key="xyz"

Now we store the response in actualResponse variable as a String. After the response is stored we compare it with assertEquals function of JSONAssert Library.

In this case, the test will pass as expectedResponse will match the actualResponse.

Failure Scenario

Now lets see another case where we change the expected response a bit. You can find the expected response in the expectedresponse.txt file. This file is different than the one which we used earlier. In this case we changed the name of Airport in the expectedresponse.txt file from

Chhatrapati Shivaji Maharaj International Airport

To

Chhatrapati Shivaji Maharaj Domestic Airport.

Now when we run the above test again, it will fail and it will specify exactly where the response did not match which we can view in the following output.

java.lang.AssertionError: candidates[formatted_address=Mumbai, Maharashtra 400099, India].name
Expected: Chhatrapati Shivaji Maharaj Domestic Airport
     got: Chhatrapati Shivaji Maharaj International Airport


    at org.skyscreamer.jsonassert.JSONAssert.assertEquals(JSONAssert.java:417)
    at org.skyscreamer.jsonassert.JSONAssert.assertEquals(JSONAssert.java:394)
    at JSONAssertTest.test01(JSONAssertTest.java:37)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:133)
    at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:598)
    at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:173)
    at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
    at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:824)
    at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:146)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.testng.TestRunner.privateRun(TestRunner.java:794)
    at org.testng.TestRunner.run(TestRunner.java:596)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:377)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:371)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:332)
    at org.testng.SuiteRunner.run(SuiteRunner.java:276)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1212)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1134)
    at org.testng.TestNG.runSuites(TestNG.java:1063)
    at org.testng.TestNG.run(TestNG.java:1031)
    at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
    at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:109)


===============================================
Default Suite
Total tests run: 1, Passes: 0, Failures: 1, Skips: 0
===============================================

In the next post, we will learn to use the strict mode and see how it works.

Β