Checks

Checks can be used to validate your request and extract elements which can be reused later

This page describes generic checks that can in theory be supported in all official protocols supported in Gatling.

Some protocols might implement specific checks, for example status for HTTP. Those are not described here, but in the documentation specific to this protocol.

Concepts

Checks are used for 2 things:

  • verifying that the response to a request matches some expectations
  • capturing some elements in the response

Checks are typically attached to the parent object with the check method. For example, on an HTTP request:

       
http("Gatling").get("https://gatling.io")
  .check(status().is(200))
http("Gatling").get("https://gatling.io")
  .check(status().is(200))
http("Gatling").get("https://gatling.io")
  .check(status().shouldBe(200))
http("Gatling").get("https://gatling.io")
  .check(status.is(200))

You can also define multiple checks at once:

       
http("Gatling").get("https://gatling.io")
  .check(
    status().not(404),
    status().not(500)
  )
http("Gatling").get("https://gatling.io")
  .check(
    status().not(404),
    status().not(500)
  )
http("Gatling").get("https://gatling.io")
  .check(
    status().not(404),
    status().not(500)
  )
http("Gatling").get("https://gatling.io")
  .check(
    status.not(404),
    status.not(500)
  )

This API provides a dedicated DSL for chaining the following steps:

  1. defining the check type
  2. extracting
  3. transforming
  4. validating
  5. naming
  6. saving

Generic check types

The following check types are generic and usually implemented on most official Gatling supported protocols.

responseTimeInMillis

Returns the response time of this request in milliseconds = the time between starting to send the request and finishing to receive the response.

       
.check(responseTimeInMillis().lte(100))
.check(responseTimeInMillis().lte(100))
.check(responseTimeInMillis().lte(100))
.check(responseTimeInMillis.lte(100))

bodyString

Return the full response body String.

       
.check(
  bodyString().is("{\"foo\": \"bar\"}"),
  bodyString().is(ElFileBody("expected-template.json"))
)
.check(
  bodyString().is("{\"foo\": \"bar\"}"),
  bodyString().is(ElFileBody("expected-template.json"))
)
.check(
  bodyString().shouldBe("""{"foo": "bar"}"""),
  bodyString().shouldBe(ElFileBody("expected-template.json"))
)
.check(
  bodyString.is("""{"foo": "bar"}"""),
  bodyString.is(ElFileBody("expected-template.json"))
)

bodyBytes

Return the full response body byte array.

       
.check(
  bodyBytes().is("{\"foo\": \"bar\"}".getBytes(StandardCharsets.UTF_8)),
  bodyBytes().is(RawFileBody("expected.json"))
)
.check(
  bodyBytes().is("{\"foo\": \"bar\"}".getBytes(StandardCharsets.UTF_8)),
  bodyBytes().is(RawFileBody("expected.json"))
)
.check(
  bodyBytes().shouldBe("""{"foo": "bar"}""".toByteArray(StandardCharsets.UTF_8)),
  bodyBytes().shouldBe(RawFileBody("expected.json"))
)
.check(
  bodyBytes.is("""{"foo": "bar"}""".getBytes(StandardCharsets.UTF_8)),
  bodyBytes.is(RawFileBody("expected.json"))
)

bodyLength

Return the length of the response body in bytes (without the overhead of computing the bytes array).

       
.check(bodyLength().is(1024))
.check(bodyLength().is(1024))
.check(bodyLength().shouldBe(1024))
.check(bodyLength.is(1024))

bodyStream

Return an InputStream of the full response body bytes, typically to transform the received bytes before processing them.

       
.check(bodyStream().transform(is -> {
  // decode the Base64 stream into a String
  try (InputStream base64Is = Base64.getDecoder().wrap(is)) {
      return new String(base64Is.readAllBytes(), StandardCharsets.UTF_8);
  } catch (IOException e) {
      throw new RuntimeException("Impossible to decode Base64 stream");
  }
}))
Not supported by Gatling JS.
.check(bodyStream().transform { inputStream ->
  // decode the Base64 stream into a String
  Base64.getDecoder().wrap(inputStream).use { base64Is ->
    String(base64Is.readAllBytes(), StandardCharsets.UTF_8)
  }
})
.check(bodyStream.transform { is =>
  // decode the Base64 stream into a String
  Using(Base64.getDecoder.wrap(is)) { base64Is =>
    new String(base64Is.readAllBytes(), StandardCharsets.UTF_8)
  }
})

substring

This check looks for the indices of the occurrences of a given substring inside the response body text.

It takes one single parameter:

  • pattern can be a plain String, a Gatling Expression Language String or a function.
       
.check(
  // with a static value
  // (identical to substring("expected").find().exists())
  substring("expected"),
  // with a a dynamic value computed from a Gatling Expression Language String
  substring("#{expectedKey}"),
  // with a dynamic value computed from a function
  substring(session -> "expectedValue"),
  substring("Error:").notExists(),
  // this will save a List<Int>
  substring("foo").findAll().saveAs("indices"),
  // this will save the number of occurrences of foo
  substring("foo").count().saveAs("counts")
)
.check(
  // with a static value
  // (identical to substring("expected").find().exists())
  substring("expected"),
  // with a a dynamic value computed from a Gatling Expression Language String
  substring("#{expectedKey}"),
  // with a dynamic value computed from a function
  substring((session) => "expectedValue"),
  substring("Error:").notExists(),
  // this will save a List<Int>
  substring("foo").findAll().saveAs("indices"),
  // this will save the number of occurrences of foo
  substring("foo").count().saveAs("counts")
)
.check(
  // with a static value
  // (identical to substring("expected").find().exists())
  substring("expected"),
  // with a dynamic value computed from a Gatling Expression Language String
  substring("#{expectedKey}"),
  // with a dynamic value computed from a function
  substring { session -> "expectedValue" },
  substring("Error:").notExists(),
  // this will save a List<Int>
  substring("foo").findAll().saveAs("indices"),
  // this will save the number of occurrences of foo
  substring("foo").count().saveAs("counts")
)
.check(
  // with a static value
  // (identical to substring("expected").find.exists)
  substring("expected"),
  // with a dynamic value computed from a Gatling Expression Language String
  substring("#{expectedKey}"),
  // with a dynamic value computed from a function
  substring(session => "expectedValue"),
  substring("Error:").notExists,
  // this will save a List<Int>
  substring("foo").findAll.saveAs("indices"),
  // this will save the number of occurrences of foo
  substring("foo").count.saveAs("counts")
)

regex

This check applies a Java regular expression pattern on the response body text.

It takes one single parameter:

  • pattern can be a plain String, a Gatling Expression Language String or a function.
       
.check(
  // with a static value without capture groups
  regex("<td class=\"number\">"),
  // with a Gatling EL without capture groups
  regex("<td class=\"number\">ACC#{account_id}</td>"),
  // with a static value with one single capture group
  regex("/private/bank/account/(ACC[0-9]*)/operations.html")
)
.check(
  // with a static value without capture groups
  regex("<td class=\"number\">"),
  // with a Gatling EL without capture groups
  regex("<td class=\"number\">ACC#{account_id}</td>"),
  // with a static value with one single capture group
  regex("/private/bank/account/(ACC[0-9]*)/operations.html")
)
.check(
  // with a static value without capture groups
  regex("""<td class="number">"""),
  // with a Gatling EL without capture groups
  regex("""<td class="number">ACC#{account_id}</td>"""),
  // with a static value with one single capture group
  regex("/private/bank/account/(ACC[0-9]*)/operations.html")
)
.check(
  // with a static value without capture groups
  regex("""<td class="number">"""),
  // with a Gatling EL without capture groups
  regex("""<td class="number">ACC#{account_id}</td>"""),
  // with a static value with one single capture group
  regex("/private/bank/account/(ACC[0-9]*)/operations.html")
)

By default, it can extract 0 or 1 capture group, so the extracted type is String. If your pattern contains more than one capture group, you must specify it with an extra step:

       
// In Java, use captureGroups(numberOfCaptureGroups) to capture List<String>
.check(
  regex("foo(.*)bar(.*)baz").captureGroups(2)
)
// In Java, use captureGroups(numberOfCaptureGroups) to capture List<String>
.check(
  regex("foo(.*)bar(.*)baz").captureGroups(2)
)
// In Kotlin, use captureGroups(numberOfCaptureGroups) to capture List<String>
.check(
  regex("foo(.*)bar(.*)baz").captureGroups(2)
)
// In Scala, use ofType[T] to capture String tuples (up to 8)
.check(
  regex("foo(.*)bar(.*)baz").ofType[(String, String)]
)

xpath

This check applies an XPath query on an XML response body.

It takes two parameters:

  • expression can be a plain String, a Gatling Expression Language String or a function.
  • namespaces is an optional List of couples of (prefix, uri). It’s mandatory as soon as your document contains namespaces.
       
.check(
  // simple expression for a document that doesn't use namespaces
  xpath("//input[@id='text1']/@value"),
  // mandatory namespaces parameter for a document that uses namespaces
  xpath("//foo:input[@id='text1']/@value", Map.of("foo", "http://foo.com"))
)
.check(
  // simple expression for a document that doesn't use namespaces
  xpath("//input[@id='text1']/@value"),
  // mandatory namespaces parameter for a document that uses namespaces
  xpath("//foo:input[@id='text1']/@value", { "foo": "http://foo.com" })
)
.check(
  // simple expression for a document that doesn't use namespaces
  xpath("//input[@id='text1']/@value"),
  // mandatory namespaces parameter for a document that uses namespaces
  xpath("//foo:input[@id='text1']/@value", mapOf("foo" to "http://foo.com"))
)
.check(
  // simple expression for a document that doesn't use namespaces
  xpath("//input[@id='text1']/@value"),
  // mandatory namespaces parameter for a document that uses namespaces
  xpath("//foo:input[@id='text1']/@value", Map("foo" -> "http://foo.com"))
)

jsonPath

JsonPath is an XPath-like syntax for JSON.

It takes one single parameter:

  • expression can be a plain String, a Gatling Expression Language String or a function.
       
.check(
  // with a static value
  jsonPath("$..foo.bar[2].baz"),
  // with a Gatling EL String
  jsonPath("$..foo.bar[#{index}].baz"),
  // with a function
  jsonPath(session -> "$..foo.bar[" + session.getInt("session") + "].baz")
)
.check(
  // with a static value
  jsonPath("$..foo.bar[2].baz"),
  // with a Gatling EL String
  jsonPath("$..foo.bar[#{index}].baz"),
  // with a function
  jsonPath((session) => "$..foo.bar[" + session.get("session") + "].baz")
)
.check(
  // with a static value
  jsonPath("$..foo.bar[2].baz"),
  // with a Gatling EL String
  jsonPath("$..foo.bar[#{index}].baz"),
  // with a function
  jsonPath { session -> "$..foo.bar[${session.getInt("session")}].baz" }
)
.check(
  // with a static value
  jsonPath("$..foo.bar[2].baz"),
  // with a Gatling EL String
  jsonPath("$..foo.bar[#{index}].baz"),
  // with a function
  jsonPath(session => s"$$..foo.bar[${session("session").as[Int]}].baz")
)

By default, it extracts Strings, meaning that non String values get serialized back into JSON. You can tell Gatling the expected type with an extra step. Note that the check will then fail if the actual value doesn’t match the expected type.

       
.check(
  jsonPath("$.foo").ofString(),
  jsonPath("$.foo").ofBoolean(),
  jsonPath("$.foo").ofInt(),
  jsonPath("$.foo").ofLong(),
  jsonPath("$.foo").ofDouble(),
  // JSON array
  jsonPath("$.foo").ofList(),
  // JSON object
  jsonPath("$.foo").ofMap(),
  // anything
  jsonPath("$.foo").ofObject()
)
.check(
  jsonPath("$.foo").ofString(),
  jsonPath("$.foo").ofBoolean(),
  jsonPath("$.foo").ofInt(),
  jsonPath("$.foo").ofLong(),
  jsonPath("$.foo").ofDouble(),
  // JSON array
  jsonPath("$.foo").ofList(),
  // JSON object
  jsonPath("$.foo").ofMap(),
  // anything
  jsonPath("$.foo").ofObject()
)
.check(
  jsonPath("$.foo").ofString(),
  jsonPath("$.foo").ofBoolean(),
  jsonPath("$.foo").ofInt(),
  jsonPath("$.foo").ofLong(),
  jsonPath("$.foo").ofDouble(),
  // JSON array
  jsonPath("$.foo").ofList(),
  // JSON object
  jsonPath("$.foo").ofMap(),
  // anything
  jsonPath("$.foo").ofObject()
)
.check(
  jsonPath("$.foo").ofType[String],
  jsonPath("$.foo").ofType[Boolean],
  jsonPath("$.foo").ofType[Int],
  jsonPath("$.foo").ofType[Long],
  jsonPath("$.foo").ofType[Double],
  // JSON array
  jsonPath("$.foo").ofType[Seq[Any]],
  // JSON object
  jsonPath("$.foo").ofType[Map[String, Any]],
  // anything
  jsonPath("$.foo").ofType[Any]
)

For example, considering the following JSON payload:

{
  "foo": 1,
  "bar": "baz"
}

… this is how you would extract an integer value:

       
.check(
  jsonPath("$.foo").ofInt().is(1)
)
.check(
  jsonPath("$.foo").ofInt().is(1)
)
.check(
  jsonPath("$.foo").ofInt().shouldBe(1)
)
.check(
  jsonPath("$.foo").ofType[Int].is(1)
)

jsonpJsonPath

Same as jsonPath but for JSONP.

jmesPath

JMESPath is a query language for JSON.

It takes one single parameter:

  • expression can be a plain String, a Gatling Expression Language String or a function.
       
.check(
  // with a static value
  jmesPath("foo.bar[2].baz"),
  // with a Gatling EL String
  jmesPath("foo.bar[#{index}].baz"),
  // with a function
  jmesPath(session -> "foo.bar[" + session.getInt("session") + "].baz")
)
.check(
  // with a static value
  jmesPath("foo.bar[2].baz"),
  // with a Gatling EL String
  jmesPath("foo.bar[#{index}].baz"),
  // with a function
  jmesPath((session) => "foo.bar[" + session.get("session") + "].baz")
)
.check(
  // with a static value
  jmesPath("foo.bar[2].baz"),
  // with a Gatling EL String
  jmesPath("foo.bar[#{index}].baz"),
  // with a function
  jmesPath { session -> "foo.bar[${session.getInt("session")}].baz" }
)
.check(
  // with a static value
  jmesPath("foo.bar[2].baz"),
  // with a Gatling EL String
  jmesPath("foo.bar[#{index}].baz"),
  // with a function
  jmesPath(session => s"foo.bar[${session("session").as[Int]}].baz")
)

By default, it extracts Strings, meaning that non String values get serialized back into JSON. You can tell Gatling the expected type with an extra step. Note that the check will then fail is the actual value doesn’t match the expected type.

       
.check(
  jmesPath("foo").ofString(),
  jmesPath("foo").ofBoolean(),
  jmesPath("foo").ofInt(),
  jmesPath("foo").ofLong(),
  jmesPath("foo").ofDouble(),
  // JSON array
  jmesPath("foo").ofList(),
  // JSON object
  jmesPath("foo").ofMap(),
  // anything
  jmesPath("foo").ofObject()
)
.check(
  jmesPath("foo").ofString(),
  jmesPath("foo").ofBoolean(),
  jmesPath("foo").ofInt(),
  jmesPath("foo").ofLong(),
  jmesPath("foo").ofDouble(),
  // JSON array
  jmesPath("foo").ofList(),
  // JSON object
  jmesPath("foo").ofMap(),
  // anything
  jmesPath("foo").ofObject()
)
.check(
  jmesPath("foo").ofString(),
  jmesPath("foo").ofBoolean(),
  jmesPath("foo").ofInt(),
  jmesPath("foo").ofLong(),
  jmesPath("foo").ofDouble(),
  // JSON array
  jmesPath("foo").ofList(),
  // JSON object
  jmesPath("foo").ofMap(),
  // anything
  jmesPath("foo").ofObject()
)
.check(
  jmesPath("foo").ofType[String],
  jmesPath("foo").ofType[Boolean],
  jmesPath("foo").ofType[Int],
  jmesPath("foo").ofType[Long],
  jmesPath("foo").ofType[Double],
  // JSON array
  jmesPath("foo").ofType[Seq[Any]],
  // JSON object
  jmesPath("foo").ofType[Map[String, Any]],
  // anything
  jmesPath("foo").ofType[Any]
)

For example, considering the following JSON payload:

{
  "foo": 1,
  "bar": "baz"
}

… this is how you would extract an integer value:

       
.check(
  jmesPath("foo").ofInt().is(1)
)
.check(
  jmesPath("foo").ofInt().is(1)
)
.check(
  jmesPath("foo").ofInt().shouldBe(1)
)
.check(
  jmesPath("foo").ofType[Int].is(1)
)

jsonpJmesPath

Same as jmesPath but for JSONP.

css

This checks lets you apply CSS Selectors on HTML response body text.

It takes two parameters:

  • selector can be a plain String, a Gatling Expression Language String or a function.
  • attribute is an optional static String if you want to target an attribute of the selected DOM nodes.
       
.check(
  // with a static value
  css("#foo"),
  // with a Gatling EL String
  css("##{id}"),
  // with a function
  css(session -> "#" + session.getString("id")),
  // with an attribute
  css("article.more a", "href")
)
.check(
  // with a static value
  css("#foo"),
  // with a Gatling EL String
  css("##{id}"),
  // with a function
  css((session) => "#" + session.get("id")),
  // with an attribute
  css("article.more a", "href")
)
.check(
  // with a static value
  css("#foo"),
  // with a Gatling EL String
  css("##{id}"),
  // with a function
  css { session -> "#${session.getString("id")}" },
  // with an attribute
  css("article.more a", "href")
)
.check(
  // with a static value
  css("#foo"),
  // with a Gatling EL String
  css("##{id}"),
  // with a function
  css(session => s"#${session("id").as[String]}"),
  // with an attribute
  css("article.more a", "href")
)

By default, it extracts Strings. In particular, if you haven’t defined the attribute parameter, it will extract the node text content. You can force Gatling to actually capture the jodd.lagarto.dom.Node with an extra step:

       
.check(
  css("article.more a", "href").ofNode()
)
Not supported by Gatling JS.
.check(
  css("article.more a", "href").ofNode()
)
.check(
  css("article.more a", "href").ofType[Node]
)

form

This check uses a CSS Selector to capture all the defined or selected input parameters in a form tag into a Map. Map values can be multivalued depending on if the input is multivalued or not (input with multiple attribute set, or multiple occurrences of the same input name, except for radio).

It takes one single parameter:

  • selector can be a plain String, a Gatling Expression Language String or a function.
       
.check(
  form("myForm")
)
.check(
  form("myForm")
)
.check(
  form("myForm")
)
.check(
  form("myForm")
)

md5 and sha1

This check computes a checksum of the response body. This can be useful to verify that a downloaded resource has not been corrupted in the process.

       
.check(
  md5().is("???"),
  sha1().is("???")
)
.check(
  md5().is("???"),
  sha1().is("???")
)
.check(
  md5().shouldBe("???"),
  sha1().shouldBe("???")
)
.check(
  md5.is("???"),
  sha1.is("???")
)

Extracting

The extraction step of the check DSL lets you filter the desired occurrence(s).

find

Filter one single element. Target the first or only possible occurrence, depending on the check type. If the check can capture multiple elements, find is identical to find(0).

It comes in 2 flavors:

  • parameterless, identical to find(0)
  • with an integer parameter that is a 0 based rank of the occurrence. Only available on checks that can return multiple values.
       
.check(
  // those 2 are identical because jmesPath can only return 1 value
  // so find is better ommitted
  jmesPath("foo"),
  jmesPath("foo").find(),
  // jsonPath can return multiple values
  // those 3 are identical so find is better ommitted
  jsonPath("$.foo"),
  jsonPath("$.foo").find(),
  jsonPath("$.foo").find(0),
  // captures the 2nd occurrence
  jsonPath("$.foo").find(1)
)
.check(
  // those 2 are identical because jmesPath can only return 1 value
  // so find is better ommitted
  jmesPath("foo"),
  jmesPath("foo").find(),
  // jsonPath can return multiple values
  // those 3 are identical so find is better ommitted
  jsonPath("$.foo"),
  jsonPath("$.foo").find(),
  jsonPath("$.foo").find(0),
  // captures the 2nd occurrence
  jsonPath("$.foo").find(1)
)
.check(
  // those 2 are identical because jmesPath can only return 1 value
  // so find is better ommitted
  jmesPath("foo"),
  jmesPath("foo").find(),
  // jsonPath can return multiple values
  // those 3 are identical so find is better ommitted
  jsonPath("$.foo"),
  jsonPath("$.foo").find(),
  jsonPath("$.foo").find(0),
  // captures the 2nd occurrence
  jsonPath("$.foo").find(1)
)
.check(
  // those 2 are identical because jmesPath can only return 1 value
  // so find is better ommitted
  jmesPath("foo"),
  jmesPath("foo").find,
  // jsonPath can return multiple values
  // those 3 are identical so find is better ommitted
  jsonPath("$.foo"),
  jsonPath("$.foo").find,
  jsonPath("$.foo").find(0),
  // captures the 2nd occurrence
  jsonPath("$.foo").find(1)
)

findAll

Return all the occurrences. Only available on checks that can return multiple values.

       
.check(
  jsonPath("$.foo").findAll()
)
.check(
  jsonPath("$.foo").findAll()
)
.check(
  jsonPath("$.foo").findAll()
)
.check(
  jsonPath("$.foo").findAll
)

findRandom

Return a random occurrence. Only available on checks that can return multiple values.

It comes in 2 flavors:

  • parameterless, identical to findRandom(1)
  • with a num int parameter and an optional failIfLess boolean parameter (default false, check will pick as many as possible) to extract several occurrences and optionally fail is the number of actual matches is less than the expected number.
       
.check(
  // identical to findRandom(1, false)
  jsonPath("$.foo").findRandom(),
  // identical to findRandom(1, false)
  jsonPath("$.foo").findRandom(1),
  // identical to findRandom(3, false)
  // best effort to pick 3 entries, less if not enough
  jsonPath("$.foo").findRandom(3),
  // fail if less than 3 overall captured values
  jsonPath("$.foo").findRandom(3, true)
)
.check(
  // identical to findRandom(1, false)
  jsonPath("$.foo").findRandom(),
  // identical to findRandom(1, false)
  jsonPath("$.foo").findRandom(1),
  // identical to findRandom(3, false)
  // best effort to pick 3 entries, less if not enough
  jsonPath("$.foo").findRandom(3),
  // fail if less than 3 overall captured values
  jsonPath("$.foo").findRandom(3, true)
)
.check(
  // identical to findRandom(1, false)
  jsonPath("$.foo").findRandom(),
  // identical to findRandom(1, false)
  jsonPath("$.foo").findRandom(1),
  // identical to findRandom(3, false)
  // best effort to pick 3 entries, less if not enough
  jsonPath("$.foo").findRandom(3),
  // fail if less than 3 overall captured values
  jsonPath("$.foo").findRandom(3, true)
)
.check(
  // identical to findRandom(1, false)
  jsonPath("$.foo").findRandom,
  // identical to findRandom(1, false)
  jsonPath("$.foo").findRandom(1),
  // identical to findRandom(3, false)
  // best effort to pick 3 entries, less if not enough
  jsonPath("$.foo").findRandom(3),
  // fail if less than 3 overall captured values
  jsonPath("$.foo").findRandom(3, failIfLess = true)
)

count

Returns the number of occurrences. Only available on checks that can return multiple values.

       
.check(
  jsonPath("$.foo").count()
)
.check(
  jsonPath("$.foo").count()
)
.check(
  jsonPath("$.foo").count()
)
.check(
  jsonPath("$.foo").count
)

Transforming

Transforming is an optional step that lets you transform the result of the extraction before trying to match it or save it.

withDefault

This optional step lets you provide a default value in case the previous step failed to capture anything.

It takes one single parameter:

  • defaultValue can be a plain String, a Gatling Expression Language String or a function that must return the same type as the expected value
       
.check(
  jsonPath("$.foo")
    .withDefault("defaultValue")
)
.check(
  jsonPath("$.foo")
    .withDefault("defaultValue")
)
.check(
  jsonPath("$.foo")
    .withDefault("defaultValue")
)
.check(
  jsonPath("$.foo")
    .withDefault("defaultValue")
)

transform

This step lets you pass a function that will only be triggered if the previous step was able to capture something.

It takes one single parameter:

  • function is of type X to another possibly different type X2
       
.check(
  jsonPath("$.foo")
    // append "bar" to the value captured in the previous step
    .transform(string -> string + "bar")
)
.check(
  jsonPath("$.foo")
    // append "bar" to the value captured in the previous step
    .transform((string) => string + "bar")
)
.check(
  jsonPath("$.foo")
    // append "bar" to the value captured in the previous step
    .transform { string -> string + "bar" }
)
.check(
  jsonPath("$.foo")
    // append "bar" to the value captured in the previous step
    .transform(string => string + "bar")
)

transformWithSession

This step is a variant of transform that lets you access the Session is order to compute the returned result.

It takes one single parameter:

  • function is of type (X, Session) to another possibly different type X2
       
.check(
  jsonPath("$.foo")
    // append the value of the "bar" attribute
    // to the value captured in the previous step
    .transformWithSession((string, session) -> string + session.getString("bar"))
)
.check(
  jsonPath("$.foo")
    // append the value of the "bar" attribute
    // to the value captured in the previous step
    .transformWithSession((string, session) => string + session.get("bar"))
)
.check(
  jsonPath("$.foo")
    // append the value of the "bar" attribute
    // to the value captured in the previous step
    .transformWithSession { string, session -> string + session.getString("bar") }
)
.check(
  jmesPath("foo")
    // append the value of the "bar" attribute
    // to the value captured in the previous step
    .transformWithSession((string, session) => string + session("bar").as[String])
)

transformOption

In contrary to transform, this step is always invoked, even when the previous step failed to capture anything.

       
.check(
  jmesPath("foo")
    // extract can be null
    .transform(extract -> Optional.of(extract).orElse("default"))
)
.check(
  jmesPath("foo")
    // extract can be null
    .transform((extract) => extract !== null ? extract : "default")
)
.check(
  jmesPath("foo")
    // extract can be null
    .transform { extract -> Optional.of(extract).orElse("default") }
)
.check(
  jmesPath("foo")
    // extract is of type Option[String]
    .transformOption(extract => extract.orElse(Some("default")))
)

transformOptionWithSession

This step is a variant of transformOption that lets you access the Session is order to compute the returned result.

       
.check(
  jmesPath("foo")
    // extract can be null
    .transformWithSession((extract, session) ->
      Optional.of(extract).orElse(session.getString("default"))
    )
)
.check(
  jmesPath("foo")
    // extract can be null
    .transformWithSession((extract, session) =>
      extract !== null ? extract : session.get("default")
    )
)
.check(
  jmesPath("foo")
    // extract can be null
    .transformWithSession { extract, session ->
      Optional.of(extract).orElse(session.getString("default"))
    }
)
.check(
  jmesPath("foo")
    // extract is of type Option[String]
    .transformOptionWithSession((extract, session) =>
      extract.orElse(Some(session("default").as[String]))
    )
)

Validating

is

Validate that the value is equal to the expected one.

It takes one single parameter:

  • expected can be a plain value whose type matches the extracted value, a Gatling Expression Language String or a function.
       
.check(
  // with a static value
  jmesPath("foo").is("expected"),
  // with a Gatling EL String (BEWARE DIFFERENT METHOD)
  jmesPath("foo").isEL("#{expected}"),
  // with a function
  jmesPath("foo").is(session -> session.getString("expected"))
)
.check(
  // with a static value
  jmesPath("foo").is("expected"),
  // with a Gatling EL String (BEWARE DIFFERENT METHOD)
  jmesPath("foo").isEL("#{expected}"),
  // with a function
  jmesPath("foo").is((session) => session.get("expected"))
)
.check(
  // with a static value
  jmesPath("foo").shouldBe("expected"),
  // with a Gatling EL String (BEWARE DIFFERENT METHOD)
  jmesPath("foo").isEL("#{expected}"),
  // with a function
  jmesPath("foo").shouldBe { session -> session.getString("expected") }
)
.check(
  // with a static value
  jmesPath("foo").is("expected"),
  // with a Gatling EL String
  jmesPath("foo").is("#{expected}"),
  // with a function
  jmesPath("foo").is(session => session("expected").as[String])
)

isNull

Validate that the extracted value is null, typically a JSON value.

       
.check(
  jmesPath("foo")
    .isNull()
)
.check(
  jmesPath("foo")
    .isNull()
)
.check(
  jmesPath("foo")
    .isNull()
)
.check(
  jmesPath("foo")
    .isNull
)

not

Validate that the extracted value is different from the expected one.

It takes one single parameter:

  • unexpected can be a plain value whose type matches the extracted value, a Gatling Expression Language String or a function.
       
.check(
  // with a static value
  jmesPath("foo").not("unexpected"),
  // with a Gatling EL String (BEWARE DIFFERENT METHOD)
  jmesPath("foo").notEL("#{unexpected}"),
  // with a function
  jmesPath("foo").not(session -> session.getString("unexpected"))
)
.check(
  // with a static value
  jmesPath("foo").not("unexpected"),
  // with a Gatling EL String (BEWARE DIFFERENT METHOD)
  jmesPath("foo").notEL("#{unexpected}"),
  // with a function
  jmesPath("foo").not((session) => session.get("unexpected"))
)
.check(
  // with a static value
  jmesPath("foo").not("unexpected"),
  // with a Gatling EL String (BEWARE DIFFERENT METHOD)
  jmesPath("foo").notEL("#{unexpected}"),
  // with a function
  jmesPath("foo").not { session -> session.getString("unexpected") }
)
.check(
  // with a static value
  jmesPath("foo").not("unexpected"),
  // with a Gatling EL String
  jmesPath("foo").not("#{unexpected}"),
  // with a function
  jmesPath("foo").not(session => session("unexpected").as[String])
)

notNull

Validate that the extracted value is not null, typically a JSON value.

       
.check(
  jmesPath("foo").notNull()
)
.check(
  jmesPath("foo").notNull()
)
.check(
  jmesPath("foo").notNull()
)
.check(
  jmesPath("foo").notNull
)

exists

Validate that the extracted value exists.

       
.check(
  jmesPath("foo").exists()
)
.check(
  jmesPath("foo").exists()
)
.check(
  jmesPath("foo").exists()
)
.check(
  jmesPath("foo").exists
)

notExists

Validate that the check didn’t match and failed to extract anything.

       
.check(
  jmesPath("foo").notExists()
)
.check(
  jmesPath("foo").notExists()
)
.check(
  jmesPath("foo").notExists()
)
.check(
  jmesPath("foo").notExists
)

in

Validate that the extracted value belongs to a given sequence or vararg.

       
.check(
  // with a static values varargs
  jmesPath("foo").in("value1", "value2"),
  // with a static values List
  jmesPath("foo").in(List.of("value1", "value2")),
  // with a Gatling EL String that points to a List in Session (BEWARE DIFFERENT METHOD)
  jmesPath("foo").inEL("#{expectedValues}"),
  // with a function
  jmesPath("foo").in(session -> List.of("value1", "value2"))
)
.check(
  // with a static values varargs
  jmesPath("foo").in("value1", "value2"),
  // with a static values List
  jmesPath("foo").in(...["value1", "value2"]),
  // with a Gatling EL String that points to a List in Session (BEWARE DIFFERENT METHOD)
  jmesPath("foo").inEL("#{expectedValues}"),
  // with a function
  jmesPath("foo").in((session) => ["value1", "value2"])
)
.check(
  // with a static values varargs
  jmesPath("foo").within("value1", "value2"),
  // with a static values List
  jmesPath("foo").within(listOf("value1", "value2")),
  // with a Gatling EL String that points to a List in Session (BEWARE DIFFERENT METHOD)
  jmesPath("foo").withinEL("#{expectedValues}"),
  // with a function
  jmesPath("foo").within { session -> listOf("value1", "value2") }
)
.check(
  // with a static values varargs
  jmesPath("foo").in("value1", "value2"),
  // with a static values Seq
  jmesPath("foo").in(Seq("value1", "value2")),
  // with a Gatling EL String that points to a Seq in Session
  jmesPath("foo").in("#{expectedValues}"),
  // with a function
  jmesPath("foo").in(session => Seq("value1", "value2"))
)

optional

Allows for the target to be missing. In this case, the check won’t fail, the following steps won’t trigger, including saveAs, meaning possibly existing value won’t be replaced nor removed.

validate

You can supply your own validator.

It takes two parameters:

  • name is the String that would be used to describe this part in case of a failure in the final error message.
  • validator is the validation logic function.
       
.check(
  jmesPath("foo")
    .validate(
      "MyCustomValidator",
      (actual, session) -> {
        String prefix = session.getString("prefix");
        if (actual == null) {
          throw new NullPointerException("Value is missing");
        } else if (!actual.startsWith(prefix)) {
          throw new IllegalArgumentException("Value " + actual + " should start with " + prefix);
        }
        return actual;
      })
)
.check(
  jmesPath("foo")
    .validate(
      "MyCustomValidator",
      (actual, session) => {
        const prefix = session.get("prefix");
        if (actual == null) {
          throw Error("Value is missing");
        } else if (!actual.startsWith(prefix)) {
          throw Error("Value " + actual + " should start with " + prefix);
        }
        return actual;
      })
)
.check(
  jmesPath("foo")
    .validate("MyCustomValidator") { actual, session ->

      val prefix: String = session.getString("prefix")!!
      if (actual == null) {
        throw NullPointerException("Value is missing")
      } else {
        require(actual.startsWith(prefix)) { "Value $actual should start with $prefix" }
        actual
      }
    }
)
.check(
  jmesPath("foo")
    .validate(
      "MyCustomValidator",
      (actual, session) => {
        import io.gatling.commons.validation._
        val prefix = session("prefix").as[String]
        actual match {
          case Some(value) if !value.startsWith(prefix) => Failure(s"Value $value should start with $prefix")
          case None                                     => Failure("Value is missing")
          case _                                        => Success(actual)
        }
      })
)

Naming

name

Naming is an optional step for customizing the name of the check in the error message in case of a check failure.

It takes one single parameter:

  • name can only be a static String.
       
.check(
  jmesPath("foo").name("My custom error message")
)
.check(
  jmesPath("foo").name("My custom error message")
)
.check(
  jmesPath("foo").name("My custom error message")
)
.check(
  jmesPath("foo").name("My custom error message")
)

Saving

saveAs

Saving is an optional step for storing the result of the check into the virtual user’s Session, so that it can be reused later. It’s only effective when the check is successful: it could match the response and passed validation.

It takes one single parameter:

  • key can only be a static String.
       
.check(
  jmesPath("foo").saveAs("key")
)
.check(
  jmesPath("foo").saveAs("key")
)
.check(
  jmesPath("foo").saveAs("key")
)
.check(
  jmesPath("foo").saveAs("key")
)

Conditional checking

checkIf

Only perform the checks when some condition holds.

       
// with a Gatling EL String condition that resolves a Boolean
.checkIf("#{bool}").then(
  jmesPath("foo")
)
// with a function
.checkIf(session -> session.getString("key").equals("executeCheck")).then(
  jmesPath("foo")
)
// with a Gatling EL String condition that resolves a Boolean
.checkIf("#{bool}").then(
  jmesPath("foo")
)
// with a function
.checkIf((session) => session.get("key") === "executeCheck").then(
  jmesPath("foo")
)
// with a Gatling EL String condition that resolves a Boolean
.checkIf("#{bool}").then(
  jmesPath("foo")
)
// with a function
.checkIf { session -> session.getString("key").equals("executeCheck") }.then(
  jmesPath("foo")
)
// with a Gatling EL String condition that resolves a Boolean
.checkIf("#{bool}") {
  jsonPath("$..foo")
}
// with a function
.checkIf(session => session("key").as[String] == "executeCheck") {
  jsonPath("$..foo")
}

Putting it all together

To help you understand the checks, here is a list of examples.

       
.check(
  // check the HTTP status is 200
  status().is(200),

  // check the HTTP status is in [200, 210]
  status().in(200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210),

  // check the response body contains 5 https links
  regex("https://(.*)").count().is(5),

  // check the response body contains 2 https links,
  // the first one to www.google.com and the second one to gatling.io
  regex("https://(.*)/.*").findAll().is(List.of("www.google.com", "gatling.io")),

  // check the response body contains a second occurrence of "someString"
  substring("someString").find(1).exists(),

  // check the response body does not contain "someString"
  substring("someString").notExists()
)
.check(
  // check the HTTP status is 200
  status().is(200),

  // check the HTTP status is in [200, 210]
  status().in(200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210),

  // check the response body contains 5 https links
  regex("https://(.*)").count().is(5),

  // check the response body contains 2 https links,
  // the first one to www.google.com and the second one to gatling.io
  regex("https://(.*)/.*").findAll().is(["www.google.com", "gatling.io"]),

  // check the response body contains a second occurrence of "someString"
  substring("someString").find(1).exists(),

  // check the response body does not contain "someString"
  substring("someString").notExists()
)
.check(
  // check the HTTP status is 200
  status().shouldBe(200),

  // check the HTTP status is in [200, 210]
  status().within(200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210),

  // check the response body contains 5 https links
  regex("https://(.*)").count().shouldBe(5),

  // check the response body contains 2 https links,
  // the first one to www.google.com and the second one to gatling.io
  regex("https://(.*)/.*").findAll().shouldBe(listOf("www.google.com", "gatling.io")),

  // check the response body contains a second occurrence of "someString"
  substring("someString").find(1).exists(),

  // check the response body does not contain "someString"
  substring("someString").notExists()
)
.check(
  // check the HTTP status is 200
  status.is(200),

  // check the HTTP status is in [200, 210]
  status.in(200 to 210),

  // check the response body contains 5 https links
  regex("https://(.*)").count.is(5),

  // check the response body contains 2 https links,
  // the first one to www.google.com and the second one to gatling.io
  regex("https://(.*)/.*").findAll.is(Seq("www.google.com", "gatling.io")),

  // check the response body contains a second occurrence of "someString"
  substring("someString").find(1).exists,

  // check the response body does not contain "someString"
  substring("someString").notExists
)

Edit this page on GitHub