In a Gatling scenario, how do doIf, doSwitch and randomSwitch each choose which chain to run, and what happens when none of them matches?
answer
- One boolean branch, two kinds of switch
- No match means skip, not fail
- Weights are percentages that must not exceed 100
- OrElse variants add the fallback chain
- doSwitch needs at least two cases
basics
~20 sdoIf runs its chain when a boolean condition holds, doSwitch matches a resolved key against case keys, and randomSwitch draws by percentage weight. When nothing matches the block is skipped, unless an OrElse variant supplies a fallback.
solid answer
~40 s`doIf(condition)` takes a Gatling EL string resolving to a boolean or a function of the session, and runs the wrapped chain only when it holds; `doIfOrElse` adds a false branch and `doIfEquals` compares two values instead. `doSwitch(expression)` resolves the expression once and runs the chain registered under the matching key — `onCase("premium").then(chain)` in the Java-API languages, `"premium" -> chain` in Scala — and it needs at least two cases. `randomSwitch()` ignores the session and draws by percentage weight, written as numbers such as `percent(60.0)`. In both switches an unmatched pass simply bypasses the block and the user continues, unless you use `doSwitchOrElse` or `randomSwitchOrElse`. Weights above 100 are rejected when the simulation is built.
code
java · 5 linesScenarioBuilder scn = scenario("journey")
.randomSwitch().on(
percent(60.0).then(http("browse").get("/products")),
percent(30.0).then(http("search").get("/search"))
);go deeper
Be ready to write a doIf and a two-branch randomSwitch, and to say that a switch picks at most one chain per pass.
Explain that weights are percentages capped at 100, that the shortfall falls through the block, and what each OrElse variant changes.
Show that you would make a fall-through observable rather than silent, because a share of users running nothing is invisible in the report.
Own how a population's behaviour mix is expressed: weights inside one scenario, or separate scenarios with their own injection profiles, and what each choice costs in readability and in the results.
## Three ways to branch Gatling's scenario DSL has one boolean branch and a family of switches. All of them are **blocks**: they wrap chains, they pick at most one of those chains per pass, and when they are done the user carries on with whatever follows the block. - **`doIf(condition)`** — runs the wrapped chain when the condition holds, and nothing otherwise. - **`doSwitch(expression)`** — resolves an expression to a value and runs the chain registered under the matching key. - **`randomSwitch()`** — ignores the session entirely and draws a chain by percentage weight. ## `doIf` and its relatives `doIf` takes a Gatling EL string that resolves to a boolean, or a function from the session to a boolean. Four variants exist: | call | what it does | |---|---| | `doIf(condition)` | runs the chain when true; skips it otherwise | | `doIfOrElse(condition)` | adds a second chain for the false branch | | `doIfEquals(actual, expected)` | compares two resolved values instead of taking a boolean | | `doIfEqualsOrElse(actual, expected)` | the same, with a false branch | In Java, Kotlin, JavaScript and TypeScript the chain attaches with `.then(...)`, and the fallback with `.orElse(...)`. In Scala the chains go in trailing parameter lists. ## `doSwitch` — matching a key `doSwitch` evaluates its expression once and compares the result against the keys you registered. Java, Kotlin, JavaScript and TypeScript register a case as `onCase("premium").then(chain)`; Scala writes `"premium" -> chain`. Two behaviours are worth remembering: 1. **It requires at least two possibilities.** A `doSwitch` with a single case is rejected when the simulation is built, not at run time. 2. **A key that matches nothing bypasses the block.** The user does not fail and does not stall; it simply runs none of the cases and continues. `doSwitchOrElse` adds a fallback chain for exactly that case. ## `randomSwitch` — weights are percentages `randomSwitch` distributes users over chains by chance. The weights are **percentages written as numbers**, so 50% is `50` and 33.3% is `33.3` — not `0.5`. Java, Kotlin, JavaScript and TypeScript write `percent(60.0).then(chain)`; Scala writes `60.0 -> chain`. - **The sum may not exceed 100.** Gatling checks this while building the block and refuses to start the simulation, reporting that the weights sum must not be bigger than 100%. - **The sum may be less than 100, and the remainder is meaningful.** Users who fall in the unallocated share **skip the whole switch** and continue with the rest of the scenario. That is a feature: `percent(60.0)` and `percent(30.0)` means 10% of users take neither branch. - **`randomSwitchOrElse`** gives that unallocated remainder a chain of its own instead of letting it fall through. Two siblings round out the family: - **`uniformRandomSwitch()`** — equal shares, no weights to write or keep summing to 100. - **`roundRobinSwitch()`** — dispatches in rotation. Despite living beside the random ones, it is deterministic, which makes it the wrong tool when you want an independent draw per user and the right one when you want an exactly even split over a small number of passes. ## Choosing - Use `doIf` when the branch is a **property of this user's state** — a flag an earlier step set, a value you extracted. - Use `doSwitch` when the branch is a **known, enumerable key**: a customer tier, a payment method, a country. - Use `randomSwitch` when you are **modelling a mix of behaviours** across the population rather than reacting to state. A weighted switch is how a single scenario expresses "60% browse, 30% search, 10% leave". - Reach for the `OrElse` variant whenever "nothing matched" is a case you want to observe rather than silently skip. Falling through a switch is invisible in the results; a fallback chain that issues a named request is not. ## Traps - **Writing weights as fractions.** `percent(0.6)` is six-tenths of one percent, not 60%. - **Assuming the shortfall is redistributed.** It is not; those users skip the block. - **Expecting a switch to loop.** It picks once and moves on; repetition is a loop block's job. - **Building a single-case `doSwitch`.** Two possibilities are the minimum; use `doIf` for one. - **Letting weights drift past 100 as cases are added.** The simulation stops starting, which is better than a silent misallocation but still a broken build.
- How would you make the unallocated share of a randomSwitch visible in the results?Use `randomSwitchOrElse` and give the remainder a chain that issues a named request, or a named group. A user who falls through a plain `randomSwitch` runs nothing and leaves no trace, so the share is invisible in the report; a fallback chain turns it into something you can count.
- What is the difference between roundRobinSwitch and uniformRandomSwitch?`uniformRandomSwitch` draws independently with equal probability, so over a small number of passes the split will be uneven. `roundRobinSwitch` dispatches in rotation, so it is deterministic and produces an exactly even split. Use the round-robin form when you want the split guaranteed rather than expected.
saying these in an interview costs you the question
- Writing randomSwitch weights as fractions such as 0.6
- Assuming an unallocated share is redistributed over the declared chains
- Expecting a switch to repeat rather than pick once
- Building a doSwitch with a single case
- Thinking an unmatched switch key fails the virtual user