skip to content

Authoring Languages

Gatling ships five SDKs for one DSL: Java, Kotlin, Scala, JavaScript and TypeScript. Interviewers probe it because the wrong import list or the wrong inject method will not compile.

on this pageshow

explore

questions

9

In Gatling, what must a Java or Kotlin simulation declare before its first request — which class does it extend, and which imports put the DSL in scope?

level: juniorimportance: must knowfreq 68%

answer

  1. One class to extend, imports per family
  2. Types from the package, methods from the class
  3. io.gatling.javaapi.core plus a static CoreDsl
  4. HttpDsl for http; JdbcDsl only when needed

basics

~10 s

A Gatling simulation in Java or Kotlin extends io.gatling.javaapi.core.Simulation and needs two imports per DSL family: the package wildcard for the types, plus a static import of CoreDsl and HttpDsl for the DSL methods.

solid answer

~30 s

A JVM simulation is an ordinary class that extends `Simulation` from `io.gatling.javaapi.core`. Putting the DSL in scope takes two imports per family: `io.gatling.javaapi.core.*` for the types (`Simulation`, `ScenarioBuilder`, `ChainBuilder`, `FeederBuilder`) and a static import of `io.gatling.javaapi.core.CoreDsl.*` for the methods and fields (`scenario`, `exec`, `atOnceUsers`, `global`). Repeat the pair for HTTP with `io.gatling.javaapi.http.*` and `io.gatling.javaapi.http.HttpDsl.*`, and add the JDBC pair only if you use `jdbcFeeder`. Both languages also import `java.time.Duration` for durations with a unit. Kotlin uses the same package and class names, writes `class Foo : Simulation()`, and omits the `static` keyword. A Scala simulation instead imports `io.gatling.core.Predef._` and `io.gatling.http.Predef._`.

code

java · 17 lines
java
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;

import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;

public class CheckoutSimulation extends Simulation {

  HttpProtocolBuilder httpProtocol = http.baseUrl("https://example.com");

  ScenarioBuilder scn = scenario("checkout")
    .exec(http("home").get("/"));

  {
    setUp(scn.injectOpen(atOnceUsers(1))).protocols(httpProtocol);
  }
}

go deeper

for a junior

Be ready to write the opening of a simulation from memory: the class it extends and the four import lines that put the core and HTTP DSL in scope.

for a middle

Explain which import supplies the types and which supplies the DSL methods, and why dropping either one produces a visibly different compile error.

for a senior

Show that you treat the imported packages as Gatling's public API boundary, and that you keep the preamble intact rather than letting editor tooling trim it.

for a principal

Own the convention: one documented preamble the team copies from a template, and a standing rule that simulations never import from a package the reference does not name.

Gatling's JVM SDKs give you no configuration file and no annotations: a simulation is an ordinary class, and everything Gatling needs to recognise it is in the class declaration and the import block at the top of the file. ## The class Gatling instantiates Gatling starts a test by loading a class you wrote and calling its no-argument constructor. In Java and Kotlin that class must extend **`io.gatling.javaapi.core.Simulation`**, whose own Javadoc reads *"The class your own Simulations must extend"* and adds a detail worth keeping: *"On contrary to other Gatling DSL components, this class is mutable."* Every other builder — `ScenarioBuilder`, `ChainBuilder`, `HttpProtocolBuilder` — is immutable and hands back a new value on each chained call. `Simulation` is the one mutable object, because it holds the populations, protocols, assertions and pause policy that `setUp` writes into it. * **Java** — `public class CheckoutSimulation extends Simulation { ... }` * **Kotlin** — `class CheckoutSimulation : Simulation() { ... }`, with parentheses, because Kotlin calls the superclass constructor in the supertype list. * **Scala** — also `extends Simulation`, but a *different* class in a different package, `io.gatling.core.scenario.Simulation`, reached through a type alias described below. Gatling's reference also warns against a class name beginning with `Test`: tools such as Maven Surefire claim every class matching that pattern and will try to launch it themselves. ## Two imports per DSL family, and what each half carries The Java API deliberately splits each family into a **package of types** and a **final class of static members**. You need both halves. | import | kind | what it puts in scope | |---|---|---| | `io.gatling.javaapi.core.*` | package wildcard | the types: `Simulation`, `ScenarioBuilder`, `ChainBuilder`, `FeederBuilder`, `Session`, `PopulationBuilder` | | `io.gatling.javaapi.core.CoreDsl.*` | static members | `scenario`, `exec`, `feed`, `csv`, `atOnceUsers`, `global`, `details`, `regex`, `jsonPath`, and the field `deploymentInfo` | | `io.gatling.javaapi.http.*` | package wildcard | `HttpProtocolBuilder`, `HttpRequestActionBuilder`, `Ws`, `Sse`, `Proxy` | | `io.gatling.javaapi.http.HttpDsl.*` | static members | `http` (both the protocol field and the `http("name")` request method), `status`, `header`, `currentLocation`, `ws`, `sse`, `sitemap` | `CoreDsl` and `HttpDsl` are declared `public final class` with private constructors — pure holders of static members. You never extend them, you import their statics. Java writes `import static ...`; Kotlin writes the same line without the keyword, because Kotlin imports members of a Java class directly. One surprise sits in that table: the extraction builders `regex`, `css`, `jsonPath`, `jmesPath`, `xpath`, `substring` and `responseTimeInMillis` live on **`CoreDsl`**, not on `HttpDsl`. Only genuinely HTTP-specific entry points such as `status`, `header` and `currentLocation` are on `HttpDsl`. Dropping the core static import therefore breaks response checks as well as scenario building. Three further families have exactly the same two-import shape and are optional: JDBC (`io.gatling.javaapi.jdbc.*` plus `JdbcDsl.*` — Gatling's own sample block marks them *"can be omitted if you don't use jdbcFeeder"*), JMS (`JmsDsl`) and Redis (`RedisDsl`). Java and Kotlin also import **`java.time.Duration`**, because that is the type the DSL takes wherever a duration carries a unit, as in `Duration.ofMinutes(5)`. ## How each missing half fails The two halves break differently, which makes the compiler message diagnostic: 1. **Only the static import.** The DSL calls resolve, but the type names do not. `extends Simulation` fails first, then every field declared as `ScenarioBuilder` or `HttpProtocolBuilder`. 2. **Only the package wildcard.** The types resolve, but `scenario(...)`, `exec(...)` and `atOnceUsers(...)` are unresolved symbols — they are statics on a class you never imported from. 3. **Missing `HttpDsl.*`.** `http` disappears in both of its forms at once: the static field that starts a protocol and the static method that starts a request. 4. **Missing `java.time.Duration`.** Only the unit-carrying overloads break. Bare-number overloads such as `nothingFor(60)`, which Gatling reads as seconds, keep compiling, so the failure looks narrower than it is. ## The boundary the import block draws Those packages are not merely convenient. Gatling's simulation reference states that *"any class that doesn't belong to those packages is considered private, not an API, and hence subject to change at any time without notice."* The source bears that out: `io.gatling.javaapi.core.internal` and `io.gatling.javaapi.http.internal` are real subpackages, and a single-level wildcard import does not reach them. A simulation that compiles only because someone imported from an `internal` package, or from a Scala core package such as `io.gatling.core.controller`, is leaning on machinery Gatling may change without notice. That is also why the same page tells you to copy the import block verbatim rather than letting an IDE tidy it.

  • Why does Gatling recommend that a Simulation class name not begin with `Test`?
    Tools such as Maven Surefire aggressively claim every class matching a `Test*` pattern and will try to launch it as one of their own. Gatling's reference calls this out explicitly. Name the class `CheckoutSimulation` rather than `TestCheckout`, so only the Gatling plugin ever runs it.
  • Which of the documented imports can a simulation that never touches a database drop?
    The JDBC pair: `io.gatling.javaapi.jdbc.*` and the static `io.gatling.javaapi.jdbc.JdbcDsl.*`. Gatling's own sample block marks them as omittable when you do not use `jdbcFeeder`. The core and HTTP pairs stay, and so does `java.time.Duration` if any step takes a duration with a unit.
  • What is the equivalent preamble in a Scala simulation?
    `import io.gatling.core.Predef._` and `import io.gatling.http.Predef._`, plus `import scala.concurrent.duration._` so that literals such as `30.seconds` compile. One import per family instead of two, because each `Predef` object carries the types and the DSL methods together.

saying these in an interview costs you the question

  • Importing only CoreDsl and expecting ScenarioBuilder to resolve
  • Extending a Gatling class from outside the io.gatling.javaapi packages
  • Believing Kotlin needs its own separate Gatling SDK artifact
  • Assuming the JDBC imports are mandatory in every simulation
open as a page

Which npm packages does a Gatling HTTP simulation written in JavaScript or TypeScript depend on, and which of them provides the gatling command-line tool?

level: juniorimportance: must knowfreq 45%

basics

~10 s

Three: @gatling.io/core for the DSL and the simulation function, @gatling.io/http for the HTTP protocol builder, and @gatling.io/cli, a dev dependency that supplies the gatling command you invoke as npx gatling.

open as a page

In a Gatling simulation file written in JavaScript or TypeScript, what must the module export, and where does the setUp function it calls come from?

level: middleimportance: must knowfreq 40%

basics

~20 s

The module's default export must be the value returned by simulation(...), imported from @gatling.io/core. That call takes one callback, and Gatling hands setUp into it as an argument — there is no class to extend and nothing to construct.

open as a page

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%

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.

open as a page

In Gatling, why does a Java or Kotlin simulation need two imports per DSL family while a Scala simulation needs only `import io.gatling.core.Predef._`?

level: middleimportance: should knowfreq 38%

basics

~20 s

Scala's Predef is one object that inherits every DSL method, aliases the types and carries the implicits, so one wildcard import covers all three. Java keeps types in a package and DSL methods as statics on CoreDsl, so each needs its own import.

open as a page

Running npx gatling run does not offer a TypeScript simulation you just added, so which folder and file-name pattern does the Gatling JavaScript CLI search, and how do you point it at a different folder?

level: middleimportance: should knowfreq 35%

basics

~10 s

By default the gatling CLI searches the src folder for files ending in .gatling.js or .gatling.ts, at that folder's root, each default-exporting a simulation. Point it elsewhere with the --sources-folder option.

open as a page

When the Gatling JavaScript CLI runs a TypeScript simulation, what is it executing the simulation on, and what does that rule out when you add an npm library to the project?

level: seniorimportance: should knowfreq 25%

basics

~20 s

Not your local Node process. The gatling CLI downloads a Gatling runtime bundle and caches it under a .gatling home directory, and runs your simulation there — so added libraries must avoid native binaries and Node-specific JavaScript APIs.

open as a page

Gatling's reference tells you never to let an IDE optimize the imports of a simulation file — what can that break, and which packages does Gatling treat as its public API?

level: seniorimportance: nice to knowfreq 26%

basics

~20 s

Optimizing imports drops members no call site names: Scala's implicits on Predef, and Java statics that are read rather than called, such as CoreDsl.deploymentInfo. Gatling's public API is only the packages its import block names; everything else is private.

open as a page

A Gatling suite is written in Java and maintained by a platform team while the product engineers write TypeScript, so how would you decide whether to move it onto Gatling's JavaScript and TypeScript SDK?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

Decide on ownership, not syntax. The DSL vocabulary and the engine are the same, so the move buys maintainability by the product engineers and costs a rewrite, an npm toolchain, and an audit for constructs the JavaScript SDK does not have.

open as a page