A team moves its API suite from a Java library like REST Assured onto Karate feature files. Which compile-time guarantees does that give up, and what does Karate offer in their place?
answer
- Ask what the build actually compiles
- Feature files are never compiled
- Steps are text, expressions are JavaScript
- Runtime failure replaces the type check
- Java.type puts logic back under the compiler
basics
~10 sEvery compile-time guarantee goes: a Karate step is text and its expressions are JavaScript, so variable, field and method names are unchecked until the scenario runs. Karate replaces them with runtime failure and Java.type.
solid answer
~50 sEssentially all of them. In a Java suite the compiler checks the method you called, the type you bound the body to and the field you read, and a refactor renames them across the project. In Karate the build compiles your launcher class, not your feature files: `* def catId = response.id` is a JavaScript expression evaluated at run time, `Then status 201` is a keyword resolved at run time, and nothing about either is verified when the project builds. What comes back is failure that is at least loud — a step Karate does not recognise fails the scenario rather than being quietly skipped, and a failed `match` fails the run. If you want the compiler for a piece of logic, move that logic into a Java class and call it from the feature with `Java.type('com.example.util.Signer')`.
code
gherkin · 14 linesFeature: nothing on these lines is checked at build time
Background:
* url baseUrl
* def Signer = Java.type('com.example.util.Signer')
Scenario: post a signed body
* def body = { amount: 100, currency: 'EUR' }
Given path 'payments'
And header X-Signature = Signer.sign(body)
And request body
When method post
Then status 201
And match response contains { currency: 'EUR' }go deeper
Know that the build compiles your launcher and your Java helpers, and never the .feature files. Everything on a step line is resolved when the scenario runs.
Explain the two unchecked things on a step - the keyword and the expression after it - and say which one fails loudly and which one can drift silently.
The real risk is the quietly wrong expression, not the typo. Argue for assertions strong enough to notice a renamed field, since nothing else will.
Decide the boundary as policy: interactions in the feature file, algorithms behind Java.type, so the team keeps the compiler exactly where correctness matters.
## What the compiler was doing for you In a Java API-test suite the test is Java source, so the ordinary compile-time contract applies to it. The method you call must exist with that signature. The type you deserialise into must have the field you then read. Rename a field on a request model and every call site either updates with the refactor or fails to compile. None of this is specific to any one library — it is what "the test is source in the same language as the code" gets you for free. ## What a Karate step is instead A step in a `.feature` file is a line of text, and Karate resolves it when the scenario runs. Two kinds of thing are on that line and neither is checked at build time: - **The keyword.** `path`, `request`, `method`, `status`, `match`, `retry until` and the rest come from a fixed table that is Karate's own. A word that is not in it is not your step definition gone missing — there are no step definitions — it is simply not a keyword. - **The expression.** Everything after the keyword is a Karate expression, which is largely JavaScript. `* def catId = response.id`, `And header X-Signature = Signer.sign(body)` and `Then match response contains { name: 'Fluffy' }` are all evaluated at run time against whatever the variables happen to hold. Here is the same idea as a table: | Checked by the Java compiler | In a Karate feature file | |---|---| | the method name you called | a keyword, resolved when the step runs | | the type of the body you sent | a JSON literal, shaped when the step runs | | a field name read off the response | a key on a map, read when the step runs | | a rename propagated to every call site | a text edit you have to find yourself | | an unused variable or unreachable branch | nothing at all | ## What Karate gives back Three things, and it is worth being honest that none of them is a type system. 1. **The failure is loud rather than silent.** The keyword table is closed, so a mistyped or invented step word fails the scenario. A suite that runs green is at least a suite whose every step was understood. 2. **The feedback loop is short.** An API suite has no browser and no compile step of its own, so "run it" is cheap in a way that makes run-time checking more tolerable than it would be elsewhere. 3. **`Java.type` puts the compiler back where it matters.** Logic you move into `com.example.util.Signer` is compiled, unit-testable and refactorable like any other class. The feature file's *call* into it is still unchecked text, but the body of the logic is not. ## Where teams actually get burnt The failure mode is not the mistyped keyword — that one fails immediately. It is the **quietly wrong expression**: - a response field the service renamed, which a JavaScript expression happily reads as undefined; - a variable whose name drifted during an edit, so a later step reads nothing; - a path that no longer reaches the data it thinks it does, under an assertion too weak to notice; - a helper function in a feature file whose argument shape changed at one of its two call sites. In Java every one of those is a compile error. In a feature file each of them is a step that runs and a `match` that has to be strong enough to catch it. That is the concrete reason the assertion style matters more in Karate than in a typed suite: the `match` is now the *only* place a shape is checked. A `contains` that names three fields is carrying weight a compiler used to carry. ## The rule of thumb worth stating Keep in the feature file what a reader should see — the request, the response shape, the expectation. Push into Java anything whose *correctness* you want checked rather than exercised: a signing routine, a date calculation, a decoder. Expressed as a boundary rather than a preference: **the feature file describes the interaction, Java owns the algorithms.** A team that puts an algorithm in a JavaScript block inside a feature file has given up the compiler and gained nothing in readability. ## How to answer this in an interview Do not soften it — "all of them" is the correct opening, and it shows you know the build does not touch feature files. Then be specific about the two unchecked things on a step, the keyword and the expression. Then name what comes back: loud runtime failure and `Java.type` for the logic you want compiled. Finish on the real risk, which is the quietly wrong expression rather than the obvious typo, because that is the answer that says you have maintained such a suite rather than read about one.
- Does `Java.type` make the call from the feature file type-safe?No. The class it names is compiled, and its method bodies are checked, but the feature file's call into it is still an unchecked expression: a wrong method name or a wrong argument shape fails when the step runs. What you gain is a compiled, unit-testable home for the logic, not a checked call site.
- A response field is renamed by the service team and the Karate suite still passes. How is that possible?Reading a missing key is not an error in a JavaScript expression, so a step that only reads the field will run. It stays green until an assertion actually covers that field — which is why the strength of the `match` matters more here than in a typed suite, where the rename would not compile.
- Which parts of a Karate project does the build actually compile?The launcher class that starts the suite, any helper classes you reach with `Java.type`, and nothing else. The `.feature` files and the JavaScript in them are resources that Karate parses and evaluates at run time.
saying these in an interview costs you the question
- Claims Karate type-checks feature files at build time
- Says a mistyped variable name is caught before the suite runs
- Thinks Java.type makes the call from the feature file type-safe
- Argues the trade is free because the tests catch everything anyway
- Names nothing that comes back in exchange for the lost checks