Search code examples
jsonperformancescalaperformance-testinggatling

Gatling :- Compare web service Json response using jsonFileFeeder


I'm using JSON feeder to compare JSON output by web services as follows,

 val jsonFileFeeder = jsonFile("test_data.json")

    val strategy = (value: Option[String], session: Session) => value.map { jsonFileFeeder =>
      val result = JSONCompare.compareJSON("expectedStr", "actualStr", JSONCompareMode.STRICT)
      if (result.failed) Failure(result.getMessage)
      else Success(value)
      }.getOrElse(Failure("Missing body"))

      val login = exec(http("Login")
       .get("/login"))
      .pause(1)
      .feed(feeder)
      .exec(http("authorization")
        .post("/auth")
        .headers(headers_10)
        .queryParam("""email""", "${email}")
        .queryParam("""password""", "${password}")
        .check(status.is(200))
        .check(bodyString.matchWith(strategy)))
      .pause(1)

But it throws error

value matchWith is not a member of io.gatling.core.check.DefaultFindChe
ckBuilder[io.gatling.http.check.HttpCheck,io.gatling.http.response.Response,String,String]
15:10:01.963 [ERROR] i.g.a.ZincCompiler$ -         .check(bodyString.matchWith(jsonFileFeeder)))

s\lib\Login.scala:18: not found: value JSONCompare
15:10:05.224 [ERROR] i.g.a.ZincCompiler$ -       val result = JSONCompare.compareJSON(jsonFileFeeder, j
sonFileFeeder, JSONCompareMode.STRICT)
               ^
15:10:05.631 [ERROR] i.g.a.ZincCompiler$ - two errors found
Compilation failed

Solution

  • Here's a sample script that semantically compares a JSON response with expected output:

    import io.gatling.core.Predef._
    import io.gatling.http.Predef._
    import io.gatling.core.json.Jackson
    import java.nio.charset.StandardCharsets.UTF_8
    import scala.concurrent.duration._
    
    class BasicSimulation extends Simulation {
      lazy val expectedJson = Jackson.parse(
          getClass.getResourceAsStream("/output.json"),
          UTF_8
        )
    
      val scn = scenario("Scenario Name")
        .exec(http("request_1")
          .get("http://localhost:8000/output.json")
          .check(bodyString.transform(Jackson.parse).is(expectedJson))
        )
    
      setUp(scn.inject(atOnceUsers(1)))
    }
    

    It assumes there is a file output.json in the resources directory (the directory that also contains your data and request-bodies).

    However, I think you should carefully consider whether this solution is right for your needs. It won't scale as well as JSONPath or regex checks (especially for large JSON files), it's inflexible, and it seems more like a functional testing task than a performance task. I suspect that if you're trying to compare JSON files in this way, then you're probably trying to solve the wrong problem.

    Note that it doesn't use jsonFile, as jsonFile is designed for use as a feeder, whereas I suspect you want to compare a single request with a hard-coded response. However, jsonFile may prove useful if you will be making a number of different requests with different parameters and expect different (known) responses. Here's an example script that takes this approach:

    import io.gatling.core.Predef._
    import io.gatling.http.Predef._
    import io.gatling.core.json.Jackson
    import scala.concurrent.duration._
    
    class BasicSimulation extends Simulation {
      val myFeed = jsonFile("json_data.json").circular
    
      val scn = scenario("Scenario Name")
        .feed(myFeed)
        .exec(http("request_1")
          .get("${targetUrl}")
          .check(bodyString.transform(Jackson.parse).is("${expectedResponse}"))
        )
    
      setUp(scn.inject(atOnceUsers(2)))
    }
    

    It assumes there is a json resource in data/json_data.json, that looks something like the following:

    [
      {
        "targetUrl":"http://localhost:8000/failure.json",
        "expectedResponse":
          {
            "success": false,
            "message": "Request Failed"
          }
      },
      {
        "targetUrl":"http://localhost:8000/success.json",
        "expectedResponse":
          {
            "success": true,
            "message": "Request Succeeded"
          }
      }
    ]
    

    The expectedResponse should be the exact JSON you expect to get back from the server. And of course you don't just have to parameterise targetUrl, you can parameterise whatever you want in this way.

    As an aside, you may also be interested to know that Gatling 2.1 is expected to allow comparing an response with a file without using hacks like these (although the current development version only supports comparing byte-for-byte, not comparing-as-json).