In a Gatling simulation, what does the setUp call do and where must it appear?
answer
- one mandatory call per simulation
- runs in the constructor, not a method
- binds a scenario to an injection profile
- returns a handle for protocols and maxDuration
- second call throws Can only call setUp once
basics
~20 ssetUp registers this simulation's populations, each one a scenario welded to an injection profile, and returns a handle for run-wide settings such as protocols and maxDuration. It must be called exactly once, from the Simulation's constructor.
solid answer
~40 s`setUp` is the one mandatory call in a Gatling simulation. It takes one or more *populations* — a scenario that has been given an injection profile — and registers them as the load this run will produce. It returns a `SetUp` handle whose chained methods configure the whole run: `protocols`, `assertions`, `maxDuration`, `throttle` and the global pause policy. It has to run in the constructor, because Gatling instantiates the simulation class through its no-argument constructor and reads the registration straight afterwards. That is why Scala puts the call bare in the class body, Kotlin inside an `init` block, Java inside an instance initializer, and JavaScript inside the callback of `simulation((setUp) => ...)`, where `setUp` arrives as an argument rather than an inherited method.
code
java · 16 linesimport static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
public class BasicSimulation extends Simulation {
HttpProtocolBuilder httpProtocol = http.baseUrl("https://example.com");
ScenarioBuilder scn = scenario("basic").exec(http("home").get("/"));
{
setUp(scn.injectOpen(atOnceUsers(1))).protocols(httpProtocol);
}
}go deeper
Be able to point at the setUp line in a simulation and say what each argument is: a scenario that has been given an injection profile.
Be ready to explain why the call has to be in the constructor, and to name where it goes in Java, Kotlin, Scala and JavaScript without looking it up.
Be ready to debug the two failure modes in someone else's project: a second setUp call, and a setUp that never runs because it sits in an uninvoked helper.
Own the decision about how much of a simulation is extracted into shared libraries, given that setUp is the one piece that cannot leave the simulation class.
`setUp` is the single call that turns a pile of Gatling builders into a runnable test. Everything else in a simulation — scenarios, protocol configuration, injection profiles, feeders — can be extracted into helper classes and shared; `setUp` is the one piece that must be present, in this class, exactly once. ## The unit it registers: a population Gatling keeps two ideas deliberately separate. A **scenario** (`scenario("checkout").exec(...)`) describes what one virtual user *does*. An **injection profile** describes *when* virtual users of that scenario start. Neither is load on its own. A **population** is the two welded together, and you weld them by calling an injection entry point on the scenario: - `scn.injectOpen(...)` or `scn.injectClosed(...)` in Java, Kotlin, JavaScript and TypeScript - `scn.inject(...)` in Scala Either way you get back a `PopulationBuilder`, and `PopulationBuilder` is the only type `setUp` accepts. Both a varargs form and a `List` form exist in every SDK, so a simulation that builds its populations programmatically can assemble the list first and still make a single call. ## Where the call must live, and why Gatling never invokes a method you name. It scans for a concrete class assignable to its `Simulation` type, calls that class's **no-argument constructor** by reflection, and then immediately reads the parameters the constructor left behind. Anything not registered by the time the constructor returns does not exist as far as the run is concerned. That one mechanism explains every language's placement: | language | where `setUp` goes | |---|---| | Scala | bare in the class body, which *is* the constructor | | Kotlin | inside an `init { }` block | | Java | inside an instance initializer block `{ ... }`, or the constructor | | JavaScript / TypeScript | inside the callback of `export default simulation((setUp) => { ... })` | The JavaScript and TypeScript case is the one that catches people out. There is no class to extend and no inherited method: `setUp` is **handed to your callback as an argument**. The generated skeletons Gatling's own recorder emits show all four shapes, and each of them ends the same way — `setUp(scn.injectOpen(atOnceUsers(1))).protocols(httpProtocol)`, with the protocol chained onto what `setUp` returned. ## The handle you get back `setUp` returns a `SetUp` object, and unusually for this DSL it is **mutable** — every scenario, chain and population builder around it returns a fresh copy when you chain on it, but `SetUp` mutates the simulation and returns itself. Chaining on it configures the run as a whole: - `protocols(...)` — protocol configuration applied to every registered population - `assertions(...)` — the conditions the finished run is judged against - `maxDuration(...)` — a wall-clock ceiling on the whole run - `throttle(...)` — a throughput ceiling over the whole run - `disablePauses()`, `constantPauses()`, `uniformPauses(...)` and the other pause-policy methods Because each of these returns the same handle, they chain in any order after the closing parenthesis of `setUp(...)`. ## Exactly once — and what happens when it is not The rule is enforced, not merely documented: 1. **Two calls fail on the spot.** The Java API throws `UnsupportedOperationException` with the message *Can only call setUp once*; Scala's version is a `require`, so it throws `IllegalArgumentException` with *requirement failed: setUp can only be called once*. Different exception types, same rule, and it is why you register several populations as several arguments to one call rather than as several calls. 2. **Zero calls fail at startup, not at compile time.** The class compiles perfectly; the run dies while reading the simulation with *No scenario configured, make sure to call setUp.* A `setUp` hidden inside a private helper the constructor never invokes produces exactly this. 3. **Every other registration rule is checked in that same startup read, not inside `setUp`.** The `setUp` call itself enforces only the once-only rule of point 1; the remaining checks run when Gatling reads the simulation after the constructor has returned — the very moment that catches the missing `setUp` of point 2. Populations may not be `null` (the message even suggests a forward-reference problem), no registered scenario may be empty, no scenario name may be empty, and scenario names must be **unique across every registered population**, sequential children included. ## Registration is not execution Nothing is injected when the constructor returns. Gatling takes the registered populations, builds the flow graph, starts the statistics engine and only then begins injecting users. `setUp` does not block, does not return results, and cannot be used to inspect a run — it is a declaration, read once, before anything starts.
- What happens when a Gatling simulation class never calls setUp at all?The class compiles fine and the run dies while reading it, with `requirement failed: No scenario configured, make sure to call setUp.` It is a startup failure rather than a compile error, so a `setUp` buried in a helper method the constructor never invokes is only ever caught at run time.
- Can a Gatling simulation build its populations dynamically and still obey the one-call rule?Yes. Both the Scala and the Java API expose a `List` overload alongside the varargs one, so you can map over configuration, collect the resulting `PopulationBuilder` objects and pass the whole list to a single `setUp` call. Build the list first; never call `setUp` once per element.
- Why does Gatling require the simulation class to have a public no-argument constructor?Because it loads the class reflectively and calls `getConstructor().newInstance()` before reading the registration. A class with only a parameterised constructor cannot be instantiated that way, and abstract classes and interfaces are skipped outright when Gatling scans for simulations.
Think of it as filing a flight plan rather than flying: the constructor hands Gatling the whole plan once, and the tower reads it the moment you stop writing.
saying these in an interview costs you the question
- Thinking setUp is called once per scenario rather than once per simulation
- Putting setUp in a helper method the constructor never calls
- Believing setUp starts the run instead of only declaring it
- Expecting a missing setUp to be caught by the compiler