In JMeter, you add Response Assertions to verify that responses are correct. In Gatling, you use checks. But Gatling checks are more powerful -- they validate, extract, and save in a single step. And at the simulation level, assertions define pass/fail criteria for the entire test. Think of checks as per-request validation and assertions as per-test-run validation.
// Check exact status
http("Get User").get("/api/users/1")
.check(status().is(200))
// Check status is in a range
http("Create User").post("/api/users")
.check(status().in(200, 201))
// Check status is NOT a specific value
http("Protected Page").get("/admin")
.check(status().not(500))// Check that body contains a string
http("Home Page").get("/")
.check(bodyString().is("OK"))
// Check with substring
http("Home Page").get("/")
.check(substring("Welcome"))
// JSON path checks (most common for APIs)
http("Get User").get("/api/users/1")
.check(
jsonPath("$.name").is("John Doe"),
jsonPath("$.email").exists(),
jsonPath("$.age").ofInt().gt(0),
jsonPath("$.roles").count().gte(1)
)
// JSON path -- save value to session
http("Get User").get("/api/users/1")
.check(
jsonPath("$.id").saveAs("userId"),
jsonPath("$.name").saveAs("userName")
)
// Regex check
http("Get Page").get("/products")
.check(
regex("Product: (.+?) -").saveAs("productName"),
regex("price\":(\\d+)").ofInt().saveAs("price")
)
// CSS selector (for HTML responses)
http("Product Page").get("/products/1")
.check(
css("h1.product-title").is("Premium Widget"),
css("span.price", "data-value").saveAs("price")
)
// XPath (for XML/SOAP responses)
http("SOAP Service").post("/ws/users")
.check(
xpath("//user/name").is("John"),
xpath("//user/id").saveAs("userId")
)// Check response time at the request level
http("Fast Endpoint").get("/api/health")
.check(
status().is(200),
responseTimeInMillis().lt(500) // Must respond in under 500ms
)
// Check response header
http("Cached Response").get("/api/config")
.check(
header("Cache-Control").is("max-age=3600"),
header("Content-Type").is("application/json")
)Checks validate individual requests. Assertions validate the entire test run. Assertions go in the setUp block and determine whether the Gatling run is a pass or fail. This is critical for CI/CD -- when assertions fail, Gatling returns a non-zero exit code, which fails your build.
{
setUp(
scenario.injectOpen(
rampUsers(500).during(Duration.ofSeconds(60))
)
).protocols(httpProtocol)
.assertions(
// Response time assertions
global().responseTime().percentile(95.0).lt(2000), // p95 < 2 seconds
global().responseTime().percentile(99.0).lt(5000), // p99 < 5 seconds
global().responseTime().max().lt(10000), // No request > 10 seconds
// Success rate assertions
global().successfulRequests().percent().gt(99.0), // > 99% success
global().failedRequests().count().lt(10L), // Less than 10 failures
// Throughput assertions
global().requestsPerSec().gte(100.0), // At least 100 req/sec
// Per-request assertions
details("Login").responseTime().percentile(95.0).lt(1000),
details("Search").successfulRequests().percent().gt(99.5)
);
}| Scope | What It Checks | Example |
|---|---|---|
| global() | All requests combined | global().responseTime().percentile(95.0).lt(2000) |
| details("name") | Specific request by name | details("Login").responseTime().mean().lt(500) |
| forAll() | Each request individually | forAll().successfulRequests().percent().gt(95.0) |
Always set assertions in your simulation, not just checks. Checks catch issues per-request during the test, but assertions determine the overall pass/fail verdict. In CI/CD, the build should fail when assertions fail. Common assertion set: p95 response time < 2 seconds AND success rate > 99%.
Key Point: Checks validate individual requests (status, body, headers). Assertions validate the entire test run (p95, success rate, throughput). Both are essential -- checks for debugging, assertions for CI/CD pass/fail.
Key Point: Checks validate per-request. Assertions validate per-test-run. Use assertions in CI/CD for automated pass/fail.