skip to content

In Gatling, how do you wrap several actions of a scenario in a named group, and how does the Java spelling differ from Scala's?

level: middleimportance: should knowfreq 40%

answer

  1. A named bracket around part of a chain
  2. Java uses .on, Scala a second list
  3. Start and end markers, not a container
  4. Groups nest into a tree

basics

~10 s

Java, Kotlin and JavaScript write group("Checkout").on(actions...); Scala writes group("Checkout")(actions...). Either way the wrapped actions are bracketed by start and end markers so Gatling records the block as its own unit, and groups can nest.

solid answer

~40 s

A group names a stretch of a scenario so the block is reported as a business step rather than only as its individual requests. In the Java API `group(name)` returns a small intermediate object whose `on(...)` method takes the wrapped actions — `group("Checkout").on(req1, req2)` — and Kotlin and the JavaScript/TypeScript SDK use the same `.on` form. Scala instead uses a second parameter list: `group("Checkout")(req1, req2)`. The name may be a fixed string, a Gatling expression-language string, or a function of the session. Groups nest, so a checkout group can contain a payment group, and the whole block is itself just a chain — you can store it in a chain value and reuse it.

code

java · 15 lines
java
import io.gatling.javaapi.core.*;

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

class GroupExample {
  {
    ChainBuilder checkout =
        group("Checkout").on(
            http("Cart").get("/cart"),
            http("Place order").post("/orders"));

    ScenarioBuilder shopper = scenario("Shopper").exec(checkout);
  }
}

go deeper

for a junior

Be ready to write a group around two requests in the SDK you use, and to say what the name is for.

for a middle

Be ready to explain that a group is a pair of markers spliced into the chain, that groups nest, and how the Java and Scala spellings differ.

for a senior

Be ready to defend a grouping scheme that stays stable across runs and does not blow up cardinality with computed names.

for a principal

Be ready to agree with stakeholders which business steps a run must report on, and to hold that vocabulary steady across releases.

A scenario made only of requests reports only requests. A group puts a name around a stretch of the chain so that the run also has a record of the **business step** — "Checkout", "Login", "Search and open a product" — rather than just the four calls that happen to implement it. ## The two spellings | SDK | form | |---|---| | Java | `group("Checkout").on(req1, req2)` | | Kotlin | `group("Checkout").on(req1, req2)` | | JavaScript / TypeScript | `group("Checkout").on(req1, req2)` | | Scala | `group("Checkout")(req1, req2)` | The divergence is not cosmetic — it is the same divergence you see in every wrapping construct across these SDKs. Scala can take a second parameter list, so the wrapped block is simply the second argument group. The Java API has no such syntax, so `group(name)` returns an intermediate object that exists only to expose `on(...)`. Kotlin and the npm SDK sit on the Java shape and inherit `.on`. A candidate who writes Scala's form in a Java simulation will not get a subtle bug — it will not compile — but the reverse habit is a common source of confusion when a team reads examples written for the other SDK. ## What a group actually is A group is **not** a container object that holds a sub-scenario. Internally, `group(name).on(chain)` produces a small chain of its own: a group-start action, then the wrapped chain's actions, then a group-end action. That triple is then spliced into the enclosing chain like any other steps. Two useful consequences follow: 1. **A group composes exactly like anything else.** `group("Checkout").on(...)` evaluates to a builder you can assign to a chain value, pass around, and `exec` from several scenarios. There is no special "group type" to learn. 2. **Groups nest naturally.** Because the markers just bracket a region of the chain, putting one group inside another produces a nested region. A virtual user's current position is tracked as a list of enclosing groups, which is how nesting is represented in the run's output as a tree. ## Naming the group In the Java API, `group` accepts either a `String` — which may be a Gatling expression-language string, so the name can interpolate a session attribute — or a `Function<Session, String>` for a name computed at run time. That is genuinely useful ("Checkout – #{paymentMethod}") and genuinely dangerous: a name that varies per user explodes the number of distinct groups in the output, which is a cardinality problem, not a Gatling problem. Keep computed names to a small, closed set of values. ## What the group buys you Beyond naming, a group records its own timing entries alongside the requests inside it, including a cumulated response time for the block. That gives you a per-business-step number to look at rather than forcing you to reconstruct one from the individual requests. What the HTML report charts for a group, and how a post-run assertion addresses a group by path, are separate surfaces with their own rules — the composition question is only how the block gets built. ## A worked shape ```java ChainBuilder browse = group("Browse").on( http("Home").get("/"), http("Category").get("/books")); ChainBuilder checkout = group("Checkout").on( http("Cart").get("/cart"), http("Place order").post("/orders")); ScenarioBuilder shopper = scenario("Shopper").exec(browse, checkout); ``` Each group is an ordinary chain value; the scenario composes them the same way it would compose ungrouped chains. ## What happens when something inside a group fails A group records more than a name. When the block ends, Gatling emits an entry carrying the group hierarchy, its start and end timestamps, a cumulated response time, a start-to-end duration and a **status**. So the outcome of what happened inside the block is carried by the group itself, not only by the individual requests — a checkout that failed at its third call is visible as a failed checkout, without a reader having to correlate four request lines by hand. Grouping changes nothing about control flow, though. A failure inside a group does not skip the rest of the group, and a group is neither a retry boundary nor a rollback boundary; those are separate error-handling constructs in the DSL. ## Practical guidance - Group by **business step**, not by technical convenience. "Checkout" is a step a product owner recognises; "Third batch of calls" is not. - Keep group names stable across runs. A renamed group is a new group, and comparing two runs across a rename is comparing nothing. - Do not nest more deeply than the report is going to be read. Two or three levels is usually the useful limit. - Remember that grouping does not change what is sent. It changes what is recorded, and nothing else about the traffic.

  • In Gatling's Java DSL, can a group name be computed from the session?
    Yes. `group` takes either a string — which may be a Gatling expression-language string interpolating a session attribute — or a `Function<Session, String>`. Use it sparingly: every distinct value becomes a distinct group in the output, so a per-user name produces unusable cardinality.
  • Can a Gatling group contain another group?
    Yes. A group is a start marker, the wrapped chain, and an end marker spliced into the enclosing chain, so nesting simply nests the markers. A virtual user's enclosing groups are tracked as a list, which is how the nesting appears as a tree in the run's output.

saying these in an interview costs you the question

  • Writing Scala's group(name)(chain) form in a Java simulation
  • Thinking a group only renames the requests inside it
  • Assuming a group is a container type rather than markers
  • Computing group names per user and exploding cardinality