You add a `Scenario Outline` with an `Examples:` table to a Karate mock feature so one block can serve several paths, and it never answers a request. What is happening?
answer
- Mock mode selects, it does not expand
- The block is skipped, not failed
- A warning in the log, nothing else
- The older line skips more than you think
- Move the variation into the body
basics
~20 sScenario Outline is not supported in Karate mock mode. While looking for a match the handler skips an outline section with a warning, so the block never replies. Write the routes out, or move the variation into one scenario's body.
solid answer
~50 sIn mock mode a scenario name is a matcher expression, and Karate never expands a `Scenario Outline` against its `Examples:` table there. While walking a feature for a match the handler recognises an outline section and skips it, logging *skipping scenario outline*; the block is never evaluated and never replies. Nothing fails loudly — one warning line in the mock's log, then whatever the next matching scenario returns, or the handler's 404. The version detail matters on the older line: **Karate 1.5.2 stops walking that feature's remaining sections** as soon as it meets an outline, so every scenario **below** it is unreachable too, while **Karate 2.x skips only the outline**. Either way the fix is the same: write the routes out as separate `Scenario` blocks, or keep one and drive the variation from data in its body, keyed on `pathParams`.
code
gherkin · 14 linesFeature: cats mock
Background:
* def cats = read('cats.json')
# a Scenario Outline here would be skipped, never expanded
Scenario: pathMatches('/cats/{id}') && methodIs('get')
* def cat = cats[pathParams.id]
* def response = cat
* def responseStatus = cat ? 200 : 404
Scenario:
* def response = { error: 'no route', uri: '#(requestUri)' }
* def responseStatus = 404go deeper
Remember that a mock feature is a router: Scenario blocks match requests, and Scenario Outline has no meaning there.
Explain why expansion cannot work when a name is a matcher, and show the replacement — one scenario plus a lookup keyed on a path parameter.
Recognise the silent-failure shape, know that the older line also strands the scenarios below the outline, and go to the mock's log first.
Set the rule that mock features are reviewed as routing tables, since nothing in the build will tell a team that a block is dead.
## Why an outline cannot work here Outside mock mode a `Scenario Outline` is expanded before execution: one copy per `Examples:` row, with `<placeholder>` substituted. A mock does not execute scenarios — it *selects* one per request by evaluating its name. There is nothing in that model for a table of rows to mean: the handler would have to choose a row before it had a match, and the name it is about to evaluate would still contain unsubstituted placeholders. So the outline is not supported, and the implementation is blunt about it: when the walk reaches an outline section it logs a warning and skips it. The consequence is a stub that is **present in the file, syntactically valid, and permanently silent**. ## What you actually observe 1. The mock starts normally — an outline is not a startup error, and nothing is validated up front. 2. Every request that the outline was supposed to serve is answered by some other scenario, or by the handler's bare 404. 3. The only trace is a warning per request in the mock's own log, naming the feature and the line of the outline. If nobody is reading the mock's log — which, in CI, is usually the case — the symptom that reaches you is a test failing on an unexpected 404 or on the catch-all's body. ## The version-scoped part The two released lines skip the outline differently, and the difference is much bigger than it looks: - **Karate 1.5.2** breaks out of the loop over that feature's sections as soon as it meets an outline. For that request, **every scenario below the outline in the same feature is never evaluated**, and the walk moves on to the next feature file if there is one. An outline dropped into the middle of a mock feature therefore disables the whole lower half of the file — including a catch-all that lives at the bottom. - **Karate 2.x** skips only the outline and keeps walking the remaining sections normally. So on the older line the reported symptom is often not "my outline does not work" but "half my mock stopped answering after someone added a block in the middle", which is a much harder bug to see. If you maintain mock features that run on both lines, keep outlines out of them entirely rather than relying on the newer behaviour. ## What to write instead | Intent | Do this | |---|---| | A handful of fixed routes | One `Scenario` each; duplication is cheap and the file reads as a routing table | | Many ids or keys, one shape | One `Scenario: pathMatches('/cats/{id}')` and a map in the `Background`, looked up with `pathParams.id` | | Variation by query or header | One scenario per branch, or one scenario that branches inside its body on `paramValue(...)` | | A large fixture set | Keep the data in a JSON file, read it once, and index it in the body | ```gherkin # instead of an outline over three ids Scenario: pathMatches('/cats/{id}') && methodIs('get') * def cat = cats[pathParams.id] * def response = cat * def responseStatus = cat ? 200 : 404 ``` That version is also better routing: it answers ids the table never listed, and it keeps the not-found case in one place. ## Operating advice - **Read the mock's log in CI.** The two warnings that matter — *skipping scenario outline* and *no scenarios matched* — are the mock telling you it did not do what the file appears to say. Neither of them changes the exit code of anything. - **Assert on a distinctive catch-all body** rather than on a bare 404, so a routing miss is distinguishable from a modelled not-found. - **Treat a mock feature as a router, not a test.** The Gherkin constructs that carry data-driven meaning in a test — outlines, examples tables, tags for selection — either do nothing or mean something different when the same file is served as a mock, and the file gives you no warning at author time. ## Why this is a senior question It is not about knowing a limitation; it is about the shape of the failure. The mock is silent, the file looks right, the only evidence is a log line nobody reads, and on one of the two released lines the blast radius extends to scenarios that have nothing to do with the outline. Candidates who have operated a shared mock recognise that class of failure immediately and start with the log rather than with the feature file.
- How would you find out that a Karate mock is skipping a scenario outline, given the tests only show a 404?Read the mock server's log for the run. The handler logs a warning naming the feature and the line of the outline on every request, and a second warning when nothing matched at all. Neither affects any exit code, so in CI you have to capture the mock's output deliberately — or give the catch-all a body that names the method and URI it saw.
- If a Karate mock feature needs to serve fifty fixture records, where does that data belong?In the `Background`, read once from a JSON file at server start, and indexed in the scenario body by a path parameter — one `pathMatches('/cats/{id}')` scenario covering all fifty. That keeps the file a routing table, handles ids the fixture does not contain in one branch, and avoids fifty near-identical blocks.
saying these in an interview costs you the question
- Expects the outline to be expanded per row
- Thinks an unsupported block fails at startup
- Assumes a skipped outline is reported to the client
- Believes an Examples table can parameterise a matcher
- Never looks at the mock server's own log