A Maven project holds three Gatling simulation classes, and mvn gatling:test fails on the CI runner because more than one simulation is available - how do you make the job run the one you want?
answer
- The plugin refuses to guess, not fails randomly
- Interactive by default, headless under CI
- Force the fully qualified class name
- -Dgatling.simulationClass or the simulationClass element
basics
~10 sForce the class. Pass -Dgatling.simulationClass=com.project.simu.CheckoutSimulation on the mvn command line, or set a simulationClass element in the plugin configuration. Under CI the goal deliberately refuses to guess when several simulations exist.
solid answer
~40 s`mvn gatling:test` runs interactively and offers the simulation classes it found. It skips that prompt in five situations: only one simulation exists; the class is forced with `-Dgatling.simulationClass=<FullyQualifiedClassName>`; non-interactive mode is forced; Maven is in batch mode (`-B`); or the `CI` environment variable is set to `true`. In the last three, with more than one simulation available the goal **fails** rather than choosing — deliberately, so a pipeline never silently runs the wrong load test. The fix is therefore to name the class: the system property per job, or a `<simulationClass>` element in the plugin's `<configuration>` if the project only ever runs one.
code
bash · 5 lines# Fails on CI: three simulations, nobody to answer the prompt
CI=true mvn gatling:test
# Name the class and the job is deterministic
mvn gatling:test -Dgatling.simulationClass=com.project.simu.CheckoutSimulationgo deeper
Recall that the fix is to name the simulation class, and that -Dgatling.simulationClass takes the fully qualified name rather than the short one.
Explain the five conditions that turn the prompt off, and that three of them fail rather than choose when several simulations are available.
Argue why failing loudly beats guessing, and decide whether the class name belongs in the build file or in the pipeline invocation.
Set the convention for the estate so every repository answers 'which simulation does this job run' the same way, in one reviewable place.
A Gatling project with one simulation class is easy: every launcher finds it and runs it. The moment a second class lands, the build tool has to decide **which** one you meant, and the plugins deliberately refuse to guess when nobody is there to ask. ## What `gatling:test` actually does `mvn gatling:test` runs in **interactive mode** and suggests the simulation class to launch. It skips the prompt in exactly five situations: 1. there is only one simulation available; 2. the class is forced with `-Dgatling.simulationClass=<FullyQualifiedClassName>`; 3. non-interactive mode is forced; 4. Maven is in batch mode (the `-B` option); 5. the `CI` environment variable is set to `true`. Cases 3, 4 and 5 disable the prompt but do **not** substitute a choice: with more than one simulation available, the goal **fails**. That is the message a CI runner produces, and it is a feature — a pipeline that guessed could run the wrong load test for months without anyone noticing. ## Fixing the three-simulation project Say the project holds `com.project.simu.CheckoutSimulation`, `com.project.simu.SearchSimulation` and `com.project.simu.LoginSimulation`, and the nightly job must run the checkout one. Two places can carry that decision: | Where | How | When it fits | |---|---|---| | The pipeline | `mvn gatling:test -Dgatling.simulationClass=com.project.simu.CheckoutSimulation` | one build serves several jobs, each pinning a different class | | The build file | `<configuration><simulationClass>com.project.simu.CheckoutSimulation</simulationClass></configuration>` | the repository always means one simulation, and the choice should be reviewable in a diff | Pick one. Carrying the same answer in both places is how a job quietly drifts away from what the build file claims. ### A third option: bind an execution per simulation If the project genuinely must run more than one simulation from a single Maven invocation, the plugin's goals can be bound to lifecycle phases through `<executions>`, and each `<execution>` can carry its own `<configuration>`. Three executions, three `<simulationClass>` values, one `mvn verify` — the goal still selects one simulation per execution, but the list of what runs is now written down in the POM where a reviewer can see it. By default an `<execution>` of `test` binds to `integration-test` and one of `enterprisePackage` to `package`. ## The same problem in the other launchers - **Gradle.** `gatlingRun` prompts under the same rules, but the switches are task options rather than system properties: `--simulation=<FullyQualifiedClassName>` forces the class, `--non-interactive` forces headless mode, and the `CI` environment variable set to true does the same. Gradle additionally has `--all`, which runs every discovered simulation sequentially in alphabetic order. - **sbt.** `sbt 'Gatling/testOnly com.project.simu.CheckoutSimulation'` names the class directly; `Gatling/testFull` runs them all. - **JavaScript/TypeScript.** `npx gatling run` asks you to choose when several simulations are found, and `--simulation "my-simulation"` bypasses the prompt. Note the argument is the simulation's **name**, matching `src/my-simulation.gatling.js` or `.gatling.ts` — not a fully qualified class name. ## Why the core cannot help you here None of this discovery lives in Gatling itself. `io.gatling.app.Gatling` parses a small option set in which `--simulation` (short `-s`) names the class, and its selection code throws `IllegalArgumentException("Missing simulation class")` when nothing was supplied. Scanning the compiled output, presenting a menu and failing loudly under CI are all plugin behaviour layered on top. That is worth knowing because it tells you where to look when the behaviour surprises you: the build-tool plugin's version, not Gatling's. Under Gatling Enterprise the selection problem repeats one level up, with different vocabulary. `mvn gatling:enterpriseStart` prompts you to choose from the **deployed simulations**, and `-Dgatling.enterprise.simulationName="<simulation name>"` bypasses the prompt. The same `CI` environment variable disables interaction there, so a pipeline hits the identical shape of problem: say which one, or be asked. ## What counts as a simulation class Discovery is not a filename convention. Gatling's own class check rejects interfaces and abstract classes, and accepts a concrete class that extends a Gatling `Simulation`. The Gradle plugin used to detect simulations by file name ending in `Simulation` and stopped doing so in version 3.11.0, detecting classes that actually extend `Simulation` instead — which also means that in Kotlin and Scala, where the class name and the file name can differ, the **class** name is what matters. ## The practical checklist - If a CI job says more than one simulation is available, do not add `-B` or set `CI` — those are what produced the failure. Name the class. - Use the fully qualified class name; a simple name is not what the option takes. - If the goal reports that the named class is not a `Simulation`, check that it is concrete and extends Gatling's `Simulation`, and that it is on the classpath the plugin runs with. - If you genuinely want all three to run, that is `--all` on Gradle or `Gatling/testFull` on sbt. On Maven it means three invocations or three bound executions, because `gatling:test` selects one simulation per invocation.
- What counts as a simulation class for the plugins' discovery?A concrete class that extends a Gatling `Simulation`. Interfaces and abstract classes are rejected. Since gatling-gradle-plugin 3.11.0 detection is based on the class extending `Simulation` rather than on a file name ending in `Simulation`, which matters in Kotlin and Scala where the two can differ.
- How does the same problem look under Gradle and the JavaScript CLI?Gradle's `gatlingRun` prompts under the same rules and takes `--simulation=<FullyQualifiedClassName>`, `--non-interactive`, or the `CI` variable; it also has `--all`. The JavaScript CLI asks you to choose when several are found and takes `--simulation "my-simulation"`, which matches a file name rather than a class name.
- Would setting the CI variable to false on the runner be a reasonable workaround?No. It would restore the interactive prompt on a machine with no one to answer it, so the job would hang or take whatever the plugin reads from a dead input stream. The failure is telling you the job has not said which simulation it means; answer that instead.
saying these in an interview costs you the question
- Thinking the CI variable makes the goal pick a simulation for you
- Expecting an alphabetical or first-found fallback when several classes exist
- Passing a simple class name where a fully qualified name is required
- Assuming Maven accepts the Gradle plugin's --simulation option