In a keyword-driven framework, what lives in the keyword table and what stays in code?
answer
- the steps left the code too
- named actions bound to implementations
- table composes, code performs
- granularity decides whether it pays
- a branch in a table is a second case
basics
~20 sThe table owns which named actions run, in what order, with what data and what expected outcome. Code owns each action's implementation: how it drives the interface, its waiting, its argument checks and its failure message.
solid answer
~40 sA keyword-driven framework moves the steps out of the code, not just the data. Each row of a case is a named business action — create envelope, add signer, send invitation, sign as — with a few arguments, and every action name is bound to one implementation written by engineers. The table therefore owns composition, data and expected outcomes; the code owns interaction, waiting, argument validation and the failure story of each keyword. Nothing conditional belongs in the table, because a branch in a table is really a second case. Most real suites are hybrids: the table drives data and step order while code owns the hard parts, and that is the shape that survives. Granularity decides whether it pays — one keyword per action a domain expert would name aloud.
code
pseudocode · 18 lines# --- authored outside code: one case, one step per line ---
case "counterparty signs a two-signer envelope":
create envelope template = "nda-v4"
add signer role = "sender", channel = "email"
add signer role = "counterparty", channel = "email"
send invitation to = "counterparty"
sign as role = "counterparty"
audit trail contains event = "SIGNED", count = 1
# --- owned by engineers: the implementation behind one keyword ---
keyword "send invitation"(to):
require(envelope_exists(),
"send invitation: no envelope has been created yet")
signer = find_signer(to)
require(signer != null,
"send invitation: no signer with role " + to)
post_invitation(envelope.id, signer.id)
wait_until(audit_contains(envelope.id, "INVITATION_SENT"), timeout = 20)go deeper
Be able to say that a keyword is a named action backed by code, and that a case is a list of those names with arguments. Knowing the difference from a data-driven table is enough at this level.
Explain the split precisely: composition, data and expected outcomes in the table; interaction, waiting, argument checks and failure messages in code. Be ready to describe why granularity at the level of business actions is the design decision that matters.
Show that you treat keywords as a public interface: reviewed signatures, documented preconditions, bounded composition depth, and a written reference so non-engineers can author rows without reading implementations.
Own the decision of whether the layer exists at all. Weigh who authors rows, how many interfaces the same table can drive, and the ongoing cost of maintaining a vocabulary alongside the production codebase.
## Three framework styles, one axis The three styles usually named together sit on a single axis: **how much of the case has left the code**. * **Data-driven** — the steps are code; only the inputs and expected outcomes live outside. One piece of logic, many rows. * **Keyword-driven** (also called table-driven or action-word) — the *steps* have left the code too. A case is a sequence of named actions with arguments, composed in a table. Each action name is bound to a code implementation somewhere behind the table. * **Hybrid** — the common landing point. The table owns the composition and the data; code owns the steps, the interaction and everything hard. Most suites that call themselves keyword-driven are hybrids, and that is not a compromise, it is the design that survives. ## The anatomy of a keyword A keyword is a named business action with a small argument list and one code implementation. In a document e-signing flow, a reasonable vocabulary is around a dozen entries: `create envelope`, `add signer`, `send invitation`, `sign as`, `decline as`, `advance clock`, `audit trail contains`. A case is then a row-per-step sequence: create envelope template = "nda-v4" add signer role = "counterparty" send invitation to = "counterparty" sign as role = "counterparty" audit trail contains event = "SIGNED", count = 1 Each keyword implementation carries obligations the table author must never have to think about: * **Argument validation and a contract check first.** `send invitation` asserts that an envelope exists before it does anything, and fails with a message naming *itself* and the missing precondition. Half the diagnosability of a keyword suite is bought here. * **Its own waiting.** A keyword returns only when the action it names has actually taken effect, so no table author ever writes a wait. * **A defined failure story.** The keyword either succeeds, or fails with a message that names the keyword, the arguments as bound, and what it observed. * **A stable signature.** Renaming an argument breaks every table row that used it, and those rows are not in the code repository's refactoring path. ## Granularity is the whole design Keyword granularity decides whether the style pays. Too fine, and the table becomes a script written in a notation with no debugger, no types and no editor help: rows like `click element`, `type text`, `wait 2 seconds`. That is a programming language with every advantage stripped out, and it is the most common way a keyword suite dies. Too coarse, and there is no reuse: a single `run the whole signing flow` keyword takes twenty arguments and nothing composes. The usable middle is one keyword per action a domain expert would name out loud. If the action does not appear in a conversation about the product, it is probably an implementation detail that belongs inside another keyword. Composite keywords — a keyword whose implementation calls other keywords — are how you keep the vocabulary small without long rows, but each level of composition is another level of indirection to unwind when something breaks. ## Who actually authors the rows The promise most often quoted for keyword-driven testing is that a non-programmer can compose cases from named steps. It is a real property of the design, and whether it is realised is genuinely contested: plenty of teams report analysts and domain experts authoring rows productively, and plenty report the vocabulary drifting into engineer-only territory within a year, at which point the layer costs more than it returns. Treat it as a claim to verify on your own team rather than a benefit you can assume in an interview answer. Two things make the promise hold when it holds. First, the vocabulary is curated deliberately — new keywords are reviewed like public interfaces, because that is what they are. Second, a keyword reference exists: a list of every keyword, its arguments, its preconditions and one example row. Without that document, only the person who wrote the implementations can author a case, and the non-programmer story is over. ## The hybrid split, stated plainly In a hybrid suite: the table owns *which* steps run, in *what* order, with *what* data and *what* expected outcome. Code owns *how* each step is performed, everything about the interface being driven, all waiting, all error handling, and all assertions of the mechanism. Nothing conditional lives in the table; a branch in a table is a second case, not a column. The pragmatic test for whether a step belongs in the table at all: could a domain expert read the row aloud and agree it describes what should happen? If the row only makes sense to someone who has read the implementation, it should have stayed in code.
- How do you decide the granularity of a keyword?One keyword per action a domain expert would name out loud. Too fine — click, type, wait — and the table becomes a script in a notation with no debugger, no types and no editor support, which is the usual way these suites die. Too coarse and nothing composes: a single run-the-whole-flow keyword takes twenty arguments and is reused nowhere. If an action never comes up in a conversation about the product, it is an implementation detail and belongs inside another keyword.
- What is a hybrid framework, and why do most suites end up there?In a hybrid the table owns the data, the step order and the expected outcomes while code owns every step implementation and everything hard about the interface. Teams land there because the pure form — pushing all logic into the table — recreates a programming language without its tooling, while pure code loses the readable case sequence and the non-engineer authoring it enables. The hybrid split is not a compromise; it is the version that survives maintenance.
- What has to exist for a non-programmer to genuinely author a case?A curated vocabulary and a written keyword reference: every keyword with its arguments, its preconditions and one example row. Whether the promise is realised is genuinely contested — some teams sustain analyst authorship for years, others watch the vocabulary drift into engineer-only territory — so treat it as a claim to verify rather than an assumed benefit. Without the reference, only the implementer can write a row and the whole rationale collapses.
Think of the keyword vocabulary as a menu and the table as the order: diners compose freely from named dishes, but nobody writes cooking instructions on the order slip.
saying these in an interview costs you the question
- Uses data-driven and keyword-driven as the same term
- Writes keywords at the level of click and type
- Puts waiting or retries into the table as steps
- Adds conditional columns instead of a second case row
- Assumes non-programmer authorship happens without a curated vocabulary
- Lets every new case add a new one-off keyword