skip to content

A Kotlin Gatling simulation fails to compile on `global().failedRequests().count().is(0L)` — what is wrong, and what are the two ways to write it?

level: middleimportance: should knowfreq 34%

answer

  1. Kotlin keywords cannot be bare method names
  2. Backticks or the alias Gatling already ships
  3. shouldBe for is, within for in
  4. Throttle step's in is aliased during

basics

~20 s

Kotlin reserves is as a keyword, so it cannot appear as a bare method name. Escape it with backticks, or call Gatling's shouldBe alias. Kotlin's in has the same problem, aliased within on conditions and during on throttle steps.

solid answer

~40 s

Gatling's DSL was designed in Scala, where `is` and `in` are ordinary identifiers; Kotlin reserves both, so the parser rejects the call before it ever looks for a method. There are two fixes: quote the name with backticks, or call the alias Gatling ships. For equality the alias is `shouldBe`, so the line becomes `global().failedRequests().count().shouldBe(0L)`. For membership it is `within(...)`, and on a throttle step builder the `in(duration)` form is aliased `during(duration)`. Every alias is an ordinary public method on the Java API class, documented as an alias and implemented as a one-line delegation, so it produces exactly the same condition as the original. There is no Kotlin-specific SDK involved.

code

kotlin · 20 lines
kotlin
import io.gatling.javaapi.core.*
import io.gatling.javaapi.core.CoreDsl.*
import io.gatling.javaapi.http.*
import io.gatling.javaapi.http.HttpDsl.*

class CheckoutSimulation : Simulation() {

  private val scn = scenario("checkout").exec(http("home").get("/"))

  init {
    setUp(scn.injectOpen(atOnceUsers(1)))
      .protocols(http.baseUrl("https://example.com"))
      .assertions(
        global().failedRequests().count().shouldBe(0L),
        details("home").failedRequests().count().`is`(0L),
        global().successfulRequests().count().within(999L, 1000L),
        global().responseTime().max().lt(1000)
      )
  }
}

go deeper

for a junior

Recall the three alias names and what each stands in for, and that backticks are the alternative spelling for the same method.

for a middle

Explain why the collision is a parse-time failure rather than a missing method, and that the alias delegates to the original with no change in behaviour.

for a senior

Show you would settle a team convention on the aliases over backticks, and that you check ported Java chains for these two tokens in review.

for a principal

Recognise the general shape: a DSL designed in one JVM language reaches another through its Java API, and reserved-word collisions are the recurring tax you plan for.

Gatling's DSL was designed in Scala, where `is` and `in` are ordinary identifiers. Kotlin reserves both as keywords, so a Kotlin simulation cannot call those methods by writing their names. ## Where the collision happens Gatling's Java API exposes three families of conditions whose most natural English names are Kotlin keywords. All three are documented with the same alert in Gatling's reference, and all three are real methods in the source: | DSL method | Kotlin problem | alias Gatling ships | where it lives | |---|---|---|---| | `is(value)` | `is` is a Kotlin keyword | `shouldBe(value)` | assertion conditions (`Assertion`) and check validators (`CheckBuilder`) | | `in(values)` | `in` is a Kotlin keyword | `within(values)` | assertion conditions (`Assertion`) and check validators (`CheckBuilder`) | | `in(duration)` | `in` is a Kotlin keyword | `during(duration)` | the throttle step builder (`ThrottleStep`), as in `reachRps(100).in(10)` | So a Kotlin assertion chain that reads `global().failedRequests().count().is(0L)` will not compile: the parser sees the keyword, not a method name. ## The two ways to write it 1. **Escape the name.** Kotlin lets you quote an identifier that collides with a keyword, so `` global().failedRequests().count().`is`(0L) `` compiles and calls the same method Java calls. 2. **Call the alias.** `global().failedRequests().count().shouldBe(0L)` is the form Gatling's own Kotlin samples use, and it is the form to prefer: it reads as ordinary code, survives copy-paste, and does not depend on a reader recognising the quoting. The same choice applies to `in`: either the quoted form or `within(...)` for a set of accepted values, and either the quoted form or `during(...)` for a throttle step's duration. ## The aliases are ordinary Java methods, not Kotlin magic This is the part candidates most often get wrong. There is **no Kotlin SDK**. Gatling ships a Scala core and a Java API; Kotlin simulations consume that Java API unchanged. `shouldBe`, `within` and `during` are therefore plain `public` methods declared on the Java API classes, each documented as *"Alias for `in` that's a reserved keyword in Kotlin"* and each implemented as a one-line delegation to the original. Three consequences follow: * **They are not different assertions.** `shouldBe(0L)` produces exactly the same condition as `is(0L)`; the alias delegates. Nothing about the verdict, the report or the exit code changes. * **Java can call them too.** Because they are ordinary Java methods, a Java simulation may write `shouldBe` — it simply has no reason to, since `is` is legal there. * **Scala has neither problem nor alias.** In Scala, `is` and `in` are legal identifiers, so `Predef` exposes them under their own names and no alias exists. ## A Kotlin assertion chain, end to end ```kotlin import io.gatling.javaapi.core.* import io.gatling.javaapi.core.CoreDsl.* import io.gatling.javaapi.http.* import io.gatling.javaapi.http.HttpDsl.* class CheckoutSimulation : Simulation() { private val scn = scenario("checkout").exec(http("home").get("/")) init { setUp(scn.injectOpen(atOnceUsers(1))) .protocols(http.baseUrl("https://example.com")) .assertions( global().failedRequests().count().shouldBe(0L), global().successfulRequests().count().within(999L, 1000L), global().responseTime().max().lt(1000) ) } } ``` Note that `lt`, `lte`, `gt`, `gte`, `between`, `around` and `deviatesAround` need no alias at all — none of those names is reserved in Kotlin. Only `is` and `in` collide, which is why the alias set is small and easy to remember. ## Two failure modes to recognise * **The compile error is unhelpful.** Because `is` and `in` are keywords, Kotlin fails at the parse stage rather than reporting "no such method". A candidate who has not met this before typically starts hunting for a missing import, which is the wrong direction: the import block is fine. * **A port from Java looks correct and is not.** Copying a Java assertion chain into a Kotlin simulation is otherwise a clean operation — the package names, the DSL class names and the method names are identical — so `is` and `in` are the only two tokens that need touching. That narrowness is what makes them easy to miss in review. ## Catching it in review The collision is narrow enough to be checked mechanically, and narrow enough to slip through when it is not. * **Grep for the two tokens.** In a Kotlin source set, `.is(` and `.in(` are the whole search. Anything they match either has to be backticked or has to move to an alias. * **Ports are the usual source.** A Java assertion or check chain copied into a Kotlin simulation is otherwise a clean move — same packages, same DSL class names, same method names — so these two tokens are the only ones that need touching, and reviewers reading for logic skate over them. * **Pick one spelling and write it down.** Gatling's own Kotlin samples use the aliases, and a team that mixes backticked calls with alias calls in the same file makes both harder to search for later. * **Do not extend the rule by analogy.** The alias set is closed at three names because only two DSL identifiers are Kotlin keywords. Inventing a fourth, or assuming a differently named condition must also have an alias, is how hallucinated method names get into a codebase.

  • Does the same alias set apply outside assertions?
    Yes. `shouldBe` and `within` are also declared on the check validators, so a Kotlin check written as `status().is(200)` fails for the same reason and becomes `status().shouldBe(200)`. The throttle step builder carries the third alias, `during`, standing in for its `in(duration)` form.
  • Do the other assertion conditions need aliases too?
    No. `lt`, `lte`, `gt`, `gte`, `between`, `around` and `deviatesAround` are not Kotlin keywords, so they are written identically in Java, Kotlin and Scala. Only `is` and `in` collide, which keeps the alias set to three names across three call sites.

saying these in an interview costs you the question

  • Believing shouldBe is a weaker assertion than is
  • Thinking the aliases live in a separate Kotlin-only SDK
  • Assuming only assertions collide, not checks or throttle steps
  • Hunting for a missing import when the parser rejects a keyword