Karate covers API tests, a mock server and a Gatling load bridge in one tool. What does driving a load run from the same `.feature` file buy, and where does that one-tool model stop paying?
answer
- Ask what is actually shared across the three
- The load run replays a functional feature file
- Assertions still evaluate under load
- An HTTP client is built per scenario
- Connection per iteration, not per virtual user
basics
~20 sOne artefact: karate-gatling points a simulation at a .feature file, so the functional scenario and its assertions become the load script. It stops paying because Karate builds an HTTP client per scenario, which under load opens a connection per iteration.
solid answer
~40 sThe buy is that there is no second script. `karate-gatling` takes a feature path — `karateFeature("classpath:features/cats-crud.feature")` — so the load run replays a scenario you already maintain, with its `match` steps intact, and a mock authored as a feature file starts from the test itself via `karate.start('cats-mock.feature')`. One language, one runtime, nothing to keep in sync. The cost is that a functional runtime is not a load client. Karate creates an HTTP client per scenario execution deliberately, so that scenarios stay isolated; under load that means a connection per iteration where a dedicated load tool keeps one per virtual user. Karate 2.x added an opt-in shared connection manager in `karate-gatling` for exactly this, and Karate 1.x has none. Assertions also run per virtual user, so client-side work sits on the measurement path.
code
gherkin · 16 linesFeature: cats CRUD
Background:
* url baseUrl
Scenario: create and read a cat
Given path 'cats'
And request { name: 'Fluffy', age: 3 }
When method post
Then status 201
* def catId = response.id
Given path 'cats', catId
When method get
Then status 200
And match response contains { name: 'Fluffy', age: 3 }go deeper
Know the shape: karate-gatling is given a feature path, so a scenario you already wrote becomes the load script, assertions and all.
Explain what is actually shared - language, runtime and artefact type - and note that the mock is a different feature file rather than the same one.
Lead with the client-per-scenario cost and the assertions on the measurement path. That is the difference between a smoke load run and capacity work.
Decide by question, not by tool: consolidation is worth it for continuous load on the real suite, and not for capacity planning that needs a purpose-built generator.
## What "one tool" actually means here It is worth being exact, because the claim is often overstated. Karate does not run the *same file* as test, mock and load. What it shares is the language, the runtime and the artefact type: - **Test.** A `.feature` file with `url`, `path`, `method`, `status` and `match` steps. - **Load.** `karate-gatling` exists in both lines of the project and takes a feature path — `karateFeature("classpath:features/cats-crud.feature")` — so the load run replays a functional scenario you already have. - **Mock.** A mock is a different feature file, but it is a feature file, started from a test with `karate.start('cats-mock.feature')` or from a Java builder, in the same process. So the honest version of the claim is: **one language and one runtime across three jobs**, and one of the three genuinely reuses the other's artefact. ## What the shared artefact buys 1. **No second script to keep in sync.** The usual failure of load testing is a simulation that drifted away from the API months ago. A load run built on the functional scenario cannot drift, because it *is* the functional scenario. 2. **Assertions survive the trip.** The `match` steps still evaluate under load, so the run is not only measuring latency — it is also checking that the service still answers correctly at concurrency. A response that degrades into an error body shows up as a failure, not as a fast request. 3. **One skill for the team.** Whoever can read the API suite can read the load scenario. 4. **The mock is in the same language.** A team that already writes feature files does not learn a second stub syntax to stand up a dependency. ## Where it stops paying: the HTTP client This is the concrete answer, and it is the one that separates a real answer from an enthusiastic one. Karate builds an HTTP client **per scenario execution**. That is a deliberate functional-suite property — per-scenario isolation, so one scenario's configuration cannot reach another's in-flight request — and it is the wrong shape for a load generator, where you want a connection reused across iterations. The project measured it on a two-host bench and states it plainly in its own source: under Gatling, Karate opened **4,000 distinct client ports where plain Gatling kept 8**. Karate 2.x added an opt-in shared connection manager in `karate-gatling` to collapse that, worth roughly a quarter of Karate's per-iteration overhead on a plaintext endpoint and more against TLS, where the avoided handshake costs two round trips and asymmetric crypto. Karate 1.x has no such class. And the option is opt-in in 2.x rather than default precisely because a shared pool gives up the isolation a functional suite is buying. Two more limits belong in the same answer: - **Assertions sit on the measurement path.** Every `match` runs per virtual user, so assertion-heavy scenarios put client-side CPU into your numbers. A load scenario often wants a thinner assertion set than the functional one it came from. - **A failed step ends the iteration.** A failing assertion fails the scenario, so the remaining steps of that virtual user's iteration never execute. Under load that turns a partly-degraded service into a run whose later endpoints were barely exercised — which is exactly when you most wanted the numbers. ## The mock side of the same argument The mock reuse is the cleaner half of the story. Because the mock is a feature file started in process, a test can stand up its dependency and tear it down without a second product, a second config format or a second lifecycle to manage in CI. The limit is scope rather than fidelity: this is an in-process test double for your own suite, not a shared stub server other teams point at. When the need is a long-lived, separately-operated stub estate, that is a different tool's job and the one-tool argument does not reach it. ## How to decide | If you need | One tool is | Because | |---|---|---| | a smoke load run in CI on the real suite | a good fit | no second artefact, assertions intact | | capacity planning at high concurrency | a poor fit | client-per-scenario, assertions on the path | | an in-process double for your own tests | a good fit | same language, same lifecycle | | a stub estate other teams consume | out of scope | that is a standalone server's job | ## How to answer this in an interview Name the buy in one sentence — the load run replays the functional feature file, so there is no second script to drift — and then go straight to the cost, because that is what is being probed. The client-per-scenario point is the strongest thing you can say: it is a deliberate functional property, it is measurable, and the project's own mitigation is opt-in and version-specific. Finish by scoping the claim honestly: one language across three jobs, with one real artefact reuse, not one file doing everything.
- Under a Karate load run, what happens to the rest of a scenario when one `match` fails?The step fails, the scenario fails, and the remaining steps of that iteration are not executed. Under load that skews the run: a service that starts returning errors mid-scenario leaves the later endpoints barely exercised, so the numbers you have for them are thin exactly when the service was worst.
- Why is Karate's per-scenario HTTP client a problem only under load?Because in a functional suite it is the point. A client per scenario means one scenario's `configure` cannot disturb another's in-flight request, and that isolation is what a test suite is buying. Under load the same property costs you connection reuse, which is why sharing a connection manager is opt-in rather than the default.
- Does the mock server make Karate a replacement for a standalone stub server?No. A Karate mock is a feature file started in your own process for your own suite's benefit, which is why it needs no second product or config format. A stub estate that other teams point at, operate and reset independently is a different job, and the one-tool argument does not stretch to it.
saying these in an interview costs you the question
- Says the same file is simultaneously the test, the mock and the load script
- Claims a functional runtime is as efficient as a dedicated load client
- Forgets that assertions still execute under load, on every virtual user
- Assumes connections are reused across iterations by default
- Treats the in-process mock as a shared stub server for other teams