Skip to content

04 — Building Scenarios

A scenario is a chain of actions that each virtual user executes in order.


HTTP requests

// GET
exec(http("Get users").get("/users"))

// POST with JSON body
exec(http("Create user").post("/users")
    .body(StringBody("""{"name":"Alice","email":"alice@example.com"}"""))
    .asJson())

// PUT
exec(http("Update user").put("/users/#{userId}")
    .body(StringBody("""{"name":"Bob"}"""))
    .asJson())

// PATCH
exec(http("Patch user").patch("/users/#{userId}")
    .body(StringBody("""{"email":"bob@example.com"}"""))
    .asJson())

// DELETE
exec(http("Delete user").delete("/users/#{userId}"))

#{variableName} is Gatling's EL (Expression Language) — it reads from the session at runtime.


Query parameters

exec(http("Search").get("/search")
    .queryParam("q", "gatling")
    .queryParam("page", "1"))

// From session
exec(http("Search").get("/search")
    .queryParam("q", "#{searchTerm}"))

// Multi-value
exec(http("Filter").get("/items")
    .multivaluedQueryParam("tag", List.of("a", "b", "c")))

Request body

// Inline JSON string
.body(StringBody("""{"key":"value"}""")).asJson()

// File from src/test/resources/bodies/
.body(RawFileBody("bodies/createUser.json")).asJson()

// Templated file (EL expressions inside the file)
.body(ElFileBody("bodies/createUser.json")).asJson()

// Form params (application/x-www-form-urlencoded)
.formParam("username", "alice")
.formParam("password", "secret")

// Multipart form
.bodyPart(StringBodyPart("field", "value"))
.bodyPart(RawFileBodyPart("file", "upload.csv").contentType("text/csv"))

Pauses (think time)

.pause(2)                          // fixed 2 seconds
.pause(1, 5)                       // uniform random 1-5 seconds
.pause(Duration.ofMillis(500))     // 500 ms

Disable pauses globally (useful for max-throughput tests):

setUp(...).disablePauses()
// or: .constantPauses() / .normalPausesWithStdDevDuration(Duration.ofMillis(100))

Loops

repeat — fixed number of iterations

repeat(5).on(
    exec(http("Poll status").get("/status"))
    .pause(1)
)

repeat with index

// Java
repeat(10, "i").on(
    exec(session -> {
        System.out.println("Iteration: " + session.getInt("i"));
        return session;
    })
)

during — run for a duration

during(Duration.ofSeconds(30)).on(
    exec(http("Flood").get("/ping"))
    .pause(Duration.ofMillis(100))
)

asLongAs — while condition is true

asLongAs(session -> session.getInt("retries") < 3).on(
    exec(http("Retry").get("/flaky"))
    .exec(session -> session.set("retries", session.getInt("retries") + 1))
)

foreach — iterate over a list in session

// session must contain "ids" as a List
foreach("#{ids}", "id").on(
    exec(http("Get item").get("/items/#{id}"))
)

Conditionals

// doIf — run block only when condition is true
doIf(session -> session.getBoolean("isAdmin")).on(
    exec(http("Admin endpoint").get("/admin"))
)

// doIfEquals — shorthand
doIfEquals("#{role}", "admin").on(
    exec(http("Admin endpoint").get("/admin"))
)

// doIfOrElse
doIfOrElse(session -> session.getBoolean("loggedIn")).then(
    exec(http("Profile").get("/profile"))
).orElse(
    exec(http("Login").post("/login").formParam("user", "guest"))
)

// doSwitch
doSwitch("#{env}")
    .on(
        onCase("prod").then(exec(http("Prod").get("https://prod.example.com/ping"))),
        onCase("staging").then(exec(http("Staging").get("https://staging.example.com/ping")))
    )

Randomised paths

randomSwitch().on(
    percent(60.0).then(exec(http("Read").get("/articles"))),
    percent(30.0).then(exec(http("Search").get("/search?q=test"))),
    percent(10.0).then(exec(http("Write").post("/articles").body(StringBody("{}")).asJson()))
)

tryMax — retry on failure

tryMax(3).on(
    exec(http("Flaky endpoint").get("/flaky"))
)

exitBlockOnFail

Stop executing the block as soon as a request fails (instead of continuing):

exitBlockOnFail().on(
    exec(http("Step 1").post("/start"))
    .exec(http("Step 2").post("/process"))
    .exec(http("Step 3").post("/finish"))
)

Full scenario example

Java

ScenarioBuilder browsAndBuy = scenario("Browse and buy")
    .exec(http("Home").get("/"))
    .pause(1, 3)
    .exec(http("List products").get("/products"))
    .pause(2)
    .exec(session -> session.set("productId", "42"))  // hardcoded for demo
    .exec(http("Product detail").get("/products/#{productId}"))
    .pause(1)
    .exec(http("Add to cart").post("/cart")
        .body(StringBody("""{"productId":"#{productId}","qty":1}"""))
        .asJson()
        .check(status().is(201)))
    .exec(http("Checkout").post("/orders")
        .body(StringBody("""{"paymentMethod":"card"}"""))
        .asJson()
        .check(status().is(201))
        .check(jsonPath("$.orderId").saveAs("orderId")))
    .exec(http("Order confirmation").get("/orders/#{orderId}")
        .check(status().is(200)));

Kotlin

val browseAndBuy = scenario("Browse and buy")
    .exec(http("Home").get("/"))
    .pause(1, 3)
    .exec(http("List products").get("/products"))
    .pause(2)
    .exec { session -> session.set("productId", "42") }
    .exec(http("Product detail").get("/products/#{productId}"))
    .pause(1)
    .exec(
        http("Add to cart").post("/cart")
            .body(StringBody("""{"productId":"#{productId}","qty":1}"""))
            .asJson()
            .check(status().`is`(201))
    )
    .exec(
        http("Checkout").post("/orders")
            .body(StringBody("""{"paymentMethod":"card"}"""))
            .asJson()
            .check(status().`is`(201))
            .check(jsonPath("$.orderId").saveAs("orderId"))
    )
    .exec(
        http("Order confirmation").get("/orders/#{orderId}")
            .check(status().`is`(200))
    )