In Gatling's assertion DSL, what do `global`, `forAll` and `details(...)` each compute over, and how do you address a request that runs inside a group?
answer
- Exactly three scopes, no more
- forAll means every request type separately
- details takes the full path, group first
- Scala joins parts with a slash operator
- Unresolvable path fails, never silently passes
basics
~20 sglobal pools every request; forAll applies the rule to each request type separately; details(path) targets one named request or group. A request inside a group needs its full path - details("Purchase", "Checkout") in Java, details("Purchase" / "Checkout") in Scala.
solid answer
~40 sThose three are the only scopes Gatling offers. `global` computes the statistic over every request in the run; `forAll` evaluates the same rule once per individual request type, so all of them must pass; `details(path)` targets one request or one group. The path is a full match, not a search, so a request declared inside `group("Purchase")` is addressed as `details("Purchase", "Checkout")` in Java, Kotlin and the JS SDK, or `details("Purchase" / "Checkout")` in Scala. A path that resolves to nothing is treated as a **failed** assertion, not a skipped one - so a renamed request turns the run red rather than green.
code
java · 16 linesimport io.gatling.javaapi.core.*;
import static io.gatling.javaapi.core.CoreDsl.*;
public class ScopedGate extends Simulation {
public ScopedGate() {
ScenarioBuilder scn = scenario("purchase");
setUp(scn.injectOpen(atOnceUsers(1)))
.assertions(
global().responseTime().max().lt(5000),
forAll().failedRequests().percent().lte(5.0),
details("Purchase", "Checkout").responseTime().percentile(95.0).lt(800)
);
}
}go deeper
Be ready to name the three scopes and to write a details path for a request that sits inside a group, in the SDK you actually use.
Be ready to explain that the path is an exact full match and that an unresolved path fails the run rather than being skipped.
Be ready to describe what each scope costs you in practice: global hides which request moved, forAll binds requests you did not intend, details breaks on a rename.
Be ready to set a convention for how request and group names are chosen, given that assertion paths are coupled to them and drift turns runs red.
## Three scopes, and only three The first link of every Gatling assertion chooses **which requests** the statistic is computed from. There are exactly three entry points, and no others: | scope | what it computes over | |---|---| | `global` | every request in the run, aggregated into one set of statistics | | `forAll` | each individual request type in turn; the rule must hold for every one of them | | `details(path)` | one named request, or one group, addressed by its path | `global` and `forAll` are the two ends of a spectrum. `global` pools every request, so a rule written on it is a statement about the run as a whole. `forAll` expands into one evaluation per named request type, so the same rule now has to survive being applied to each request separately — including the ones you barely thought about. ## `details(path)` is a full-path match, not a search `details` is where most of the surprises live. The path is described as a Unix-like filesystem path, and it behaves like one in the strictest sense: **the parts you supply must equal the request's complete path**, group prefixes included. That means a request declared inside a group is *not* reachable by its own name alone: ```java // scenario: group("Purchase").on(exec(http("Checkout").get("/checkout"))) details("Checkout") // does NOT resolve - the real path is Purchase/Checkout details("Purchase", "Checkout") // resolves ``` Gatling's own test suite pins this: an assertion whose path parts do not match a recorded request path is reported as unresolvable, and an unresolvable assertion **fails**. That is the safe default, and it is the single most useful thing to know about this scope. A typo in a request name, a request renamed in the scenario but not in the assertion, or a request that never actually executed does not produce a green run with a quietly skipped rule — it produces a red run. ## Spelling the path, by language The path is assembled differently depending on which SDK you are writing: 1. **Scala** composes the parts with a `/` operator on strings: `details("Purchase" / "Checkout")`. 2. **Java, Kotlin and the JavaScript/TypeScript SDK** pass the parts as separate arguments: `details("Purchase", "Checkout")`. Both build the same list of path parts. Writing the Scala form in Java is a compile error, and writing `details("Purchase/Checkout")` in either is worse than a compile error — it is a single path part containing a slash, which will never match anything and will therefore fail at the end of the run. ## When the path names a group A path may address a group rather than a request. Two things then change, and both matter: - A response-time assertion on a group is matched against the group's **cumulated response time** — the time inside the group when requests were actually in flight, which is the group's elapsed duration minus the pauses. It is *not* the wall-clock time a virtual user spent between entering and leaving the group. - Count statistics on a group count **group executions**, not the requests underneath it. A group holding five requests and entered ten times has `allRequests().count()` of 10, not 50, and `details("Purchase").failedRequests().percent()` is the share of `Purchase` runs recorded KO — a group execution is KO when something inside it failed — rather than the failure rate of the requests in the flow. ## Message-driven protocols name the check, not the request For WebSockets, the name in `details(...)` is the name of the **check**, not the name of the request — the string you passed to `ws.checkTextMessage("...")` or `ws.checkBinaryMessage("...")`. Server-sent events behave the same way: `sse.checkMessage("...")` carries a name, and the SSE state machine logs that check name as the recorded action name on both success and failure, which is exactly what a `details(...)` path is matched against. Gatling's reference calls out only the WebSocket case, so SSE is the one that catches people twice over. Either way these are the places where the path is not built from request names, and they are easy to miss because everything else about the chain looks identical. ## Choosing between them, briefly Each scope buys a different failure mode, purely as a matter of what the grammar computes: - `global` gives one rule and one verdict, and it aggregates across request types, so it will not tell you *which* request moved. - `forAll` gives coverage with no maintenance, but it binds every named request, including a warm-up call or a health probe you never meant to hold to the same budget. - `details(...)` is precise and deliberate, and it is the only one that carries a maintenance cost: rename the request in the scenario and the assertion stops resolving, which shows up as a failed run rather than a skipped rule.
- What does a response-time assertion on `details("Purchase")` actually measure when `Purchase` is a group?The group's cumulated response time - the time inside the group during which requests were in flight, which is the group's elapsed duration minus the pauses. It is not the wall-clock time a virtual user spent between entering and leaving the group, so a long think time inside the group does not inflate it.
- Why does `details("Checkout")` fail for a request declared inside `group("Purchase")`?Because the path parts must equal the request's complete path, group prefix included. `Checkout` alone does not match `Purchase/Checkout`, so the assertion cannot be resolved against any recorded statistic, and an unresolvable assertion is reported as failed at the end of the run.
- What does `details(...)` name for a WebSocket?The name of the check, not the name of the request - the string passed to `ws.checkTextMessage("...")` or `ws.checkBinaryMessage("...")`. SSE behaves identically: `sse.checkMessage("...")` supplies the path part there, because the SSE state machine logs the check's own name as the action name. Those message-driven protocols are where the path is not built from request names, and it is easy to miss because the rest of the chain looks identical to an HTTP assertion.
saying these in an interview costs you the question
- Assuming an unmatched details path is skipped rather than failed
- Writing details("Group/Request") as one slash-joined string
- Thinking forAll means the rule must hold for at least one request
- Reading a group response-time assertion as the group's total duration