skip to content

In a Gradle build using the io.gatling.gradle plugin, which dependency configuration makes a library visible to your simulations, and where does the plugin expect the simulation sources?

level: middleimportance: should knowfreq 36%

answer

  1. Gatling gets its own source set
  2. src/gatling/java, kotlin, scala, resources
  3. gatling, gatlingImplementation, gatlingRuntimeOnly
  4. Other configurations never reach the simulations

basics

~20 s

Declare it in gatlingImplementation, or in gatling, or in gatlingRuntimeOnly. Dependencies added to any other configuration are not available to simulations. Sources live in the gatling source set: src/gatling/java, kotlin or scala, with resources in src/gatling/resources.

solid answer

~30 s

The plugin creates a dedicated Gradle source set named `gatling`, so simulations go in `src/gatling/java`, `src/gatling/kotlin` or `src/gatling/scala`, and feeders, request bodies and `gatling.conf` in `src/gatling/resources`. It also declares three configurations — `gatling`, `gatlingImplementation` and `gatlingRuntimeOnly` — where the last two extend `gatling`. A library declared in the ordinary `implementation` configuration is **not** available to simulations, which is the usual surprise. Your own `src/main` and `src/test` classes are added to the Gatling classpath by default, controlled by the `includeMainOutput` and `includeTestOutput` flags in the `gatling` extension.

code

kotlin · 4 lines
kotlin
dependencies {
    "gatlingImplementation"("org.apache.commons:commons-lang3:3.4")
    "gatlingRuntimeOnly"("cglib:cglib-nodep:3.2.0")
}

go deeper

for a junior

Recall the two directories that matter: simulations under src/gatling with your language's name, resources under src/gatling/resources.

for a middle

Explain the three Gatling configurations, how gatlingImplementation and gatlingRuntimeOnly extend gatling, and why other configurations are invisible to simulations.

for a senior

Diagnose the classpath: separate a missing source set directory from a dependency declared in the wrong configuration from a transitive library the include flags never carried.

for a principal

Decide how much production and test code simulations may reuse, since the include flags make that coupling the default rather than a choice.

The Gradle plugin does not bolt Gatling onto the `test` task. It gives Gatling its own **source set** and its own **dependency configurations**, and everything that surprises people about it follows from that one design choice. ## The gatling source set Applying `io.gatling.gradle` creates a Gradle source set named `gatling`, with the directory layout you would expect from any source set: | Directory | Holds | |---|---| | `src/gatling/java` | simulation sources in Java | | `src/gatling/kotlin` | simulation sources in Kotlin | | `src/gatling/scala` | simulation sources in Scala | | `src/gatling/resources` | feeders, request bodies, `gatling.conf`, `logback.xml` | These are defaults, not laws — the ordinary Gradle source-set API can point them elsewhere, for example `sourceSets { gatling { scala.srcDir "folder1" } }` to add a directory or `scala.srcDirs = ["folder1"]` to replace the set. But if a newly written simulation is simply not found, the first thing to check is that it is under `src/gatling`, not `src/test`. ## The three configurations The plugin declares `gatling`, `gatlingImplementation` and `gatlingRuntimeOnly`. `gatlingImplementation` and `gatlingRuntimeOnly` both **extend** `gatling`, so anything declared in `gatling` is inherited by the other two. The plugin puts the Gatling libraries themselves into `gatling`. The rule that matters is stated bluntly in the plugin's documentation: dependencies added to configurations **other than** these three are not available within Gatling simulations. So this does not work: ``` dependencies { implementation("org.apache.commons:commons-lang3:3.4") // invisible to simulations } ``` and this does: ``` dependencies { gatlingImplementation("org.apache.commons:commons-lang3:3.4") } ``` Choosing among the three follows the ordinary Gradle meanings: `gatlingImplementation` for a library your simulation code compiles against, `gatlingRuntimeOnly` for something needed only at run time such as a JDBC driver, and `gatling` for a dependency you want on both. ## Your own code is already there Project classes from `src/main` and test classes from `src/test` are added to the Gatling classpath by default, so a simulation can reuse a production DTO or a test helper without any extra wiring. Two flags in the `gatling` extension control that: - `includeMainOutput`, default `true` — include `src/main` classes and resources - `includeTestOutput`, default `true` — include `src/test` classes and resources Note the asymmetry that catches people out: these flags carry your **classes and resources**, not the third-party dependencies those classes were compiled against. A helper in `src/test` that uses a library declared in `testImplementation` will be on the Gatling classpath while the library it needs is not, and the failure arrives at run time as a `NoClassDefFoundError`. ## The gatling extension Alongside the source set and the configurations, the plugin adds a `gatling` extension block that carries the run's own settings rather than the build's: - `gatlingVersion` — which Gatling to resolve; it defaults to the first three digits of the plugin's own version, which is why the plugin version and the Gatling version track each other. - `scalaVersion` — the Scala version matching your Gatling version. - `jvmArgs` and `systemProperties` — what the forked simulation JVM is launched with. Note that **setting `jvmArgs` replaces the defaults** rather than appending to them. - `simulation` — a fully qualified class name, the standing answer to "which simulation". - `includeMainOutput` and `includeTestOutput` — the two flags above. The `GatlingRunTask` type behind `gatlingRun` exposes similar options, and they fall back to the extension: an option not set on the task takes the value from the global `gatling` block. You can also instantiate your own `GatlingRunTask` instances if you want named tasks for particular simulations. ## Multi-project builds Apply the plugin only to the subprojects that actually hold simulations. Those subprojects can still depend on other subprojects in the usual Gradle way, so a shared client library or a set of domain objects does not need to move. Applying the plugin everywhere gives every subproject a `gatling` source set and a set of Gatling tasks it will never use. ## What the plugin stopped doing for you Version 3.11.0 of the Gradle plugin made three changes that still surprise people upgrading: 1. It no longer applies the `java` and `scala` plugins automatically. Applying the plugin for your language is now the build author's job. 2. It no longer detects simulations by file name ending in `Simulation`; it detects classes that actually extend `Simulation`. That matters in Kotlin and Scala, where a file can hold a class with a different name. 3. The per-simulation `gatlingRun-<FullyQualifiedClassName>` task was dropped in favour of `gatlingRun --simulation=<FullyQualifiedClassName>`. ## Compatibility and the wider picture The plugin requires at least Gradle 7.6. If you have a multi-project build, apply it only to the subprojects that actually hold simulations; those subprojects can still depend on other subprojects. And keep in mind the counterpart rule to all of this: the Maven and sbt plugins take the opposite approach and run simulations out of the project's ordinary test sources, which is why `gatling.conf` lives in `src/test/resources` there and in `src/gatling/resources` here.

  • How do you stop your project's test classes reaching the Gatling classpath?
    Set `includeTestOutput = false` in the `gatling` extension; `includeMainOutput = false` does the same for `src/main`. Both default to `true`, which is why simulations can normally reuse production and test helper code with no extra wiring.
  • Why must a Gradle Gatling project apply the java or scala plugin itself?
    Since gatling-gradle-plugin 3.11.0 the Gatling plugin no longer applies them for you, so applying the plugin for your language is the build author's job. Gatling's demo projects for Java and Scala show the required `plugins` block.
  • A test helper on the Gatling classpath fails with NoClassDefFoundError. What happened?
    `includeTestOutput` carries your compiled `src/test` classes and resources, not the libraries they were compiled against. A helper depending on something declared in `testImplementation` needs that library declared in a Gatling configuration too.

saying these in an interview costs you the question

  • Declaring simulation libraries in implementation and expecting them at run time
  • Putting Gradle simulations under src/test instead of src/gatling
  • Assuming the plugin still applies the java and scala plugins for you
  • Believing includeTestOutput also carries the test dependencies themselves