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?
answer
- One class to extend, imports per family
- Types from the package, methods from the class
- io.gatling.javaapi.core plus a static CoreDsl
- HttpDsl for http; JdbcDsl only when needed
basics
~10 sA 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 sA 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 linesimport 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
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.
Explain which import supplies the types and which supplies the DSL methods, and why dropping either one produces a visibly different compile error.
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.
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