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 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
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))
)