skip to content

In a Gatling scenario, a checkout step calls a payment provider you are not permitted to load test - how would you decide what to put in its place?

level: principalimportance: nice to knowfreq 22%

answer

  1. A stand-in for a call you cannot make
  2. Named action with a chosen response time
  3. Outcome and session update are configurable
  4. The number is an assumption, not data

basics

~20 s

Gatling's dummy action stands in for a call you cannot make: a chosen response time, a success or failure outcome, and an optional session update. The judgement is which number you attribute and whether the report admits it.

solid answer

~40 s

`dummy("Payment", 250)` inserts an action named Payment that reports a 250 ms response time without touching the network, so a surrounding `group("Checkout")` still measures the whole business step end to end and downstream steps still see a coherent session. `.withSuccess(false)` turns it into a failure so you can exercise the failure path, and `.withSessionUpdate(session -> ...)` writes the attributes the real call would have returned. The response time may also be a Gatling expression-language string or a function, so it can vary per user. What you cannot do is pretend the result measures that dependency: the number is an assumption you chose, and the run's report should say so. If that provider's latency is a material part of what you are validating, a stand-in is not enough.

code

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

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

class DummyExample {
  {
    ChainBuilder checkout =
        group("Checkout").on(
            http("Cart").get("/cart"),
            dummy("Payment", "#{randomInt(200,400)}")
                .withSessionUpdate(session -> session.set("paymentRef", "TEST-1")),
            http("Place order").post("/orders"));

    ChainBuilder declined = exec(dummy("Payment", 250).withSuccess(false));
  }
}

go deeper

for a junior

Be ready to recall that Gatling has a dummy action which emulates a call with a chosen response time and outcome.

for a middle

Be ready to configure one: the response time forms, withSuccess for the outcome, and withSessionUpdate for the attributes the real call would have set.

for a senior

Be ready to justify the response time you attributed, model failures rather than defaulting to success, and name what the run therefore did not measure.

for a principal

Be ready to own the call: when substitution keeps a run honest, when it invalidates the question being asked, and how that caveat reaches the people reading the result.

Sooner or later a scenario contains a call you are not allowed to make at load: a payment provider whose sandbox rate-limits you, a partner API with a contractual call budget, a mainframe nobody will let you push. You have three options — call it anyway, delete the step, or substitute something. Gatling gives you a first-class way to substitute, and the interesting part is the judgement around it, not the syntax. ## What `dummy` gives you `dummy(name, responseTime)` builds an action that **emulates** a remote call. It occupies a place in the chain, it is named, it is timed, and it produces a sample — but no packet leaves the machine. Its configuration surface is small and deliberate: - **The name** may be a fixed string, a Gatling expression-language string, or a function of the session. - **The response time** may be a plain integer number of milliseconds, an expression-language string such as `"#{randomInt(200,400)}"`, or a function of the session — so it can vary per virtual user rather than being a constant. - **`withSuccess(...)`** sets the outcome, as a boolean, an expression-language string or a function. If you never call it, the outcome is a success. - **`withSessionUpdate(...)`** takes a session function and applies it as part of the action, so the stand-in can write the attributes the real call would have produced — an order reference, a token, a status — and the steps after it keep working unchanged. Because it is an ordinary action builder, it composes exactly like a request: you can put it inside a group, inside a loop, or store the whole chain in a value. ## Why not just delete the step Deleting the call is the tempting shortcut and it is usually the worst option, for a specific reason: the surrounding **group** timing silently changes meaning. A `Checkout` group that used to contain four calls now contains three, and its number is no longer comparable with any earlier run. A stand-in keeps the shape of the business step intact and makes the substitution visible in the output as a named action, where a reader can see it. ## The judgement, stated as questions 1. **Is that dependency part of what this run is validating?** If the question is "can our checkout hold 500 orders a minute", and the payment provider is on the critical path, then a stand-in answers a different question than the one asked. Say so before the run, not after. 2. **What response time do you attribute, and on what basis?** A measured production percentile for that call is defensible. A round number someone liked is not. Whatever you pick, it is an input to the result, not an output of it. 3. **Should it ever fail?** Real dependencies fail. `withSuccess(false)`, driven by an expression that fails a small share of users, exercises the error path that a permanently green stand-in never will. 4. **What does the stand-in remove from the system under test?** It removes the connection, the TLS handshake, the serialisation, the thread or connection held during the wait — all real costs. A dummy with the right response time does not reproduce the resource the real call would have occupied. 5. **How is it recorded?** The substitution belongs in the run's description, in the simulation's name, or in a comment a reader will actually see. An artefact that hides its own assumptions is worse than no artefact. ## A worked shape ```java ChainBuilder checkout = group("Checkout").on( http("Cart").get("/cart"), dummy("Payment", "#{randomInt(200,400)}") .withSessionUpdate(session -> session.set("paymentRef", "TEST-1")), http("Place order").post("/orders")); ``` The group still spans the whole business step, the stand-in is visibly named `Payment` in the output, and the order request downstream finds the reference it expects. ## When a stand-in is the wrong answer - When the provider is the thing under test. - When the real call holds a scarce resource — a connection from a small pool, a worker thread — whose exhaustion is the failure mode you are hunting. Consider a local stub that really occupies the connection instead. - When nobody will read the caveat. A number without its assumption travels further than the assumption does, and the version that travels is the wrong one. ## The position worth defending Substitution is legitimate engineering, not cheating, **provided** the substitution is named in the output, its parameters are chosen from evidence, and the report says which tier the run did not measure. That is the whole of it, and it is a call a lead should own rather than leaving to whoever writes the scenario.

  • What outcome does a Gatling dummy action report if you never call withSuccess?
    Success. The outcome is optional and defaults to a success when it is left undefined, which is worth knowing because a scenario full of unconfigured stand-ins is guaranteed to look perfect. If the real dependency fails some of the time, model that explicitly rather than inheriting the default.
  • Can a Gatling dummy action's response time vary per virtual user?
    Yes. The response time argument accepts a plain integer of milliseconds, a Gatling expression-language string such as `"#{randomInt(200,400)}"`, or a function of the session. A varying value avoids the tell-tale flat line a constant produces, though the distribution you pick is still your assumption.
  • Why not simply delete the untestable step from the scenario?
    Because the enclosing group's timing then covers a different set of calls, so the number stops being comparable with earlier runs and the omission is invisible to whoever reads the report. A named stand-in keeps the business step's shape and puts the substitution on the page.

It is a stand-in on a film set. The scene still runs to time and the blocking still works, but you are not filming the star, and nobody should cut the trailer from that footage.

saying these in an interview costs you the question

  • Believing a dummy action sends a real network request
  • Treating the chosen response time as a measurement
  • Deleting the step and keeping the group's old timings
  • Leaving every stand-in on its default success outcome