Q29 of 40 · Karate
Explain how Karate Gatling integrates performance testing with the same feature files.
KarateSeniorkarategatlingperformance-testingload-testingreuse
Short answer
Short answer: Add the karate-gatling dependency and create a Gatling simulation that references existing .feature files via KarateProtocol. The same Karate scenarios that run as functional tests now drive load. Set throughput, user counts, and assertion thresholds in the Gatling simulation class — no duplication between functional and performance test scripts.
Detail
Dependency:
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-gatling</artifactId>
<version>1.4.1</version>
<scope>test</scope>
</dependency>
Simulation class:
class CreateUserSimulation extends Simulation {
val protocol = karateProtocol(
"/users" -> Nil,
"/users/{id}" -> Nil
)
val create = scenario("Create User")
.exec(karateFeature("classpath:features/users/create-user.feature"))
setUp(
create.inject(
rampUsers(50).during(30.seconds),
constantUsersPerSec(10).during(60.seconds)
)
).protocols(protocol)
.assertions(
global.responseTime.percentile(95).lte(500),
global.successfulRequests.percent.gte(99.0)
)
}
Key points:
karateFeatureruns the .feature file for each virtual user — each user executes the full scenariokarateProtocoldeclares URL patterns so Gatling can aggregate stats per path- Assertions in
setUpfail the build if p95 > 500ms or error rate > 1% - The Karate feature runs against a real API — Gatling provides the concurrency and reporting
What changes from functional tests: thread count (Gatling injects many virtual users), no JUnit assertions (Gatling assertions in the simulation), and response time percentiles replace correctness assertions as the primary metric.
// EXAMPLE
CheckoutPerfSimulation.scala
import com.intuit.karate.gatling.KarateProtocol
import com.intuit.karate.gatling.PreDef._
import io.gatling.core.Predef._
import scala.concurrent.duration._
class CheckoutPerfSimulation extends Simulation {
val protocol = karateProtocol(
"/cart" -> Nil,
"/checkout" -> Nil,
"/orders/{id}" -> Nil
)
// Feature file already used for functional testing — reused here
val checkoutScenario = scenario("Full Checkout Flow")
.exec(karateFeature("classpath:features/orders/checkout.feature"))
setUp(
checkoutScenario.inject(
atOnceUsers(1), // warm up
rampUsers(20).during(10.seconds), // ramp to 20 concurrent
constantUsersPerSec(5).during(60.seconds) // sustain 5 rps for 1 minute
)
).protocols(protocol)
.assertions(
global.responseTime.percentile(95).lte(800), // p95 < 800ms
global.failedRequests.percent.lte(1.0) // < 1% errors
)
}// WHAT INTERVIEWERS LOOK FOR
Understanding that the same .feature file drives both functional and load tests (no duplication), how karateProtocol() aggregates stats per URL pattern, and setting meaningful assertion thresholds in the simulation. The ramp-then-sustain injection pattern is a Gatling best practice.
// COMMON PITFALL
Running the Karate Gatling simulation during the regular JUnit test suite — it will inject 50 concurrent users against the test environment, causing other tests to fail from load-induced latency. Gatling simulations run separately (different Maven phase or profile).