Inside a Karate feature file, what does `karate.start('cats-mock.feature')` return, and how long does the mock it starts stay alive?
answer
- It hands back an object, not a port number
- Ask why an object rather than nothing
- The default port is chosen for you
- Its Background has already run once
basics
~20 sA MockServer object, Karate's own handle on the running mock. The mock's Background has already run by the time the call returns. Read .port off it for the port actually bound; it serves until stopped or the JVM exits.
solid answer
~40 sIt returns a `MockServer` - Karate's own class, the handle on the mock that is now running. The argument is either a path string or a JSON config whose only mandatory key is `mock`; `port`, `ssl`, `cert`, `key`, `pathPrefix` and `arg` are optional, and the keys of an `arg` map become variables the mock feature can read. With no `port`, Karate binds a free ephemeral one, which is why the idiomatic line is `* def port = karate.start('cats-mock.feature').port` - you cannot hard-code a number you did not choose. By the time the call returns, the mock's `Background` has already executed once and the server is listening. The server, and everything its `Background` and Scenarios have accumulated since, lives until you call `stop()` on the returned object or the JVM ends.
code
gherkin · 8 linesBackground:
* def server = karate.start('cats-mock.feature')
* url 'http://localhost:' + server.port + '/cats'
Scenario: the mock is already serving
* path 'kitty'
* method get
* status 404go deeper
Learn the idiom and why it is written that way: capture the returned object, read its port, and build your url from that rather than a hard-coded number.
Be able to say what has already happened when the call returns - parsed, Background run once, globals seeded, port bound - and which config keys the JSON form takes.
Manage the lifetime deliberately: a server-lifetime object handed to you in a scenario-lifetime context will outlive the test unless you stop it, and its state outlives it with it.
Set the convention for who starts and stops shared mocks in a suite, and whether isolation comes from a server per consumer or from a reset contract on one.
## What comes back `karate.start(...)` is the way to raise a mock from inside a running Karate feature, without dropping into Java. It returns an instance of Karate's own `MockServer` class - a live handle, not a description of one. Two members matter from a feature file: - **`port`** - the port the server actually bound. This is the reason the call returns an object at all. - **`stop()`** - shuts the server down. The argument comes in two shapes. A plain string is treated as the path to the mock feature and resolved the same way `read()` resolves a path. A JSON object gives you the rest: | Key | Meaning | |---|---| | `mock` | path to the mock feature file - the only mandatory key | | `port` | the port to bind; omitted means a dynamic one | | `ssl` | serve over HTTPS | | `cert` / `key` | certificate and key files to use with `ssl` | | `pathPrefix` | a prefix stripped from the path before matching | | `arg` | a map whose keys become variables in the mock feature | ## Why the returned port is the point The default port is dynamic. That is deliberate: a suite that hard-codes 8080 for its stub collides with itself the moment two things run at once, and collides with whatever else on the machine already wanted 8080. Letting the operating system choose and then **reading the choice back** is the whole reason the call hands you an object, and it is why the canonical line reads as one expression that starts a server and captures its port in the same breath. If you do pin a port with `{ mock: '...', port: 9000 }`, you have taken that problem back on yourself. ## What has already happened when it returns By the time you hold the object: 1. The mock feature has been parsed. 2. Its `Background` has executed - once, in full. 3. Its variables are in the handler's globals map. 4. The port is bound and the server is accepting connections. All four, in that order, before the next step of your feature runs. Two consequences follow. There is no race between starting the mock and calling it: if `karate.start` returned, the mock is ready. And if the `Background` failed, `karate.start` **threw** instead of returning - so a variable holding a `MockServer` is proof that start-up succeeded. ## Lifetime The server runs until something stops it. Nothing about a scenario ending, a feature ending or a request completing takes it down. In practice that means: - **Its state lives exactly as long as it does.** The globals its `Background` seeded, and everything the Scenarios have written back since, are held by that handler. Losing the reference does not reset them; the server keeps serving. - **`stop()` on the returned object is the explicit end.** Call it when the suite is finished with the mock, and be aware that everything the mock accumulated goes with it. - **The JVM ending is the implicit end.** For a mock raised for the length of a test run, that is often all the shutdown there is. - **Starting it twice gives you two servers.** Each call builds a fresh handler on a fresh port, re-runs the `Background`, and shares nothing with the first. That is the isolation lever if one accumulating store is causing tests to interfere. ## Using it well The pattern the mock is designed around is: start it, capture the port, point the feature's `url` at that port, and let the mock's own retained state do the work of a backing store for the rest of the run. Because the port is captured rather than assumed, the same feature works whether the mock is running or a real service is. The piece people trip on is lifetime versus scope. `karate.start` gives you a **server-lifetime** object from inside a **scenario-lifetime** context, and the two do not line up on their own. If it matters that the next test sees a clean mock, that is a decision you have to make - a fresh server, or a scenario in the mock that resets its own store - because nothing in the object's lifecycle will make it for you.
- Why does `karate.start` return an object instead of just starting the server?Because the port defaults to a dynamic one, and you need to read back what was actually bound. The returned `MockServer` carries `port` for exactly that, plus `stop()`. Hard-coding a port is possible but reintroduces the collisions the dynamic default avoids.
- You call `karate.start` twice on the same mock feature. Do the two servers share the store their `Background` created?No. Each call builds a separate handler with its own globals map and re-runs the `Background` from scratch, on its own port. They are fully isolated, which is the lever to reach for when one shared accumulating mock is making tests interfere with each other.
- If `karate.start` returned normally, what do you already know about the mock?That the feature parsed, its `Background` ran to completion once, its variables are in the handler's globals, and the port is bound and accepting connections. A failing `Background` step throws out of the call instead, so holding the object is itself proof that start-up succeeded.
saying these in an interview costs you the question
- Thinks the call returns the port number itself
- Hard-codes a port instead of reading the bound one
- Expects the mock to stop when the scenario ends
- Assumes two started mocks share their retained state
- Believes the Background runs lazily on the first request