Gherkin Data Tables⚓︎
Gherkin data tables are a friendly way to put several related examples beside a Gherkin step. They let a scenario say, "these users exist" or "these content items are available" without turning every value into a separate sentence.
Given the users exist
| name | role | active |
| Asha | admin | yes |
| Bruno | editor | no |
To a reader, that table already has meaning. Asha is an admin. Bruno is an editor. One user is active and the other is not.
Inside Python, though, the table is just nested strings:
[
["name", "role", "active"],
["Asha", "admin", "yes"],
["Bruno", "editor", "no"],
]
That simplicity is useful. It is also where small parsing decisions begin to scatter across a test suite.
The invisible work⚓︎
Every table needs a few quiet decisions before test code can safely use it:
- which row contains labels
- which labels are required
- whether extra labels are allowed
- how cells become numbers, booleans, lists, dates, enums, or domain objects
- what an empty cell means
- what error should point back to the feature file when a value is wrong
Without a table layer, that work often appears directly inside step functions:
headers, *rows = datatable
users = []
for row in rows:
values = dict(zip(headers, row, strict=True))
users.append(
{
"name": values["name"],
"role": values["role"],
"active": values["active"].lower() in {"yes", "true", "1"},
}
)
This is not bad code for one small table. The problem is that every new table invites another slightly different version of the same glue.
The table still contains text
A cell that looks like yes is still text. A cell that looks like 30 is
still text. The table only becomes reliable when the project decides what
those words mean.
Where the confusion starts⚓︎
The common trap is assuming Python will guess the table meaning correctly.
That is why table parsing should be deliberate. If a feature file says no,
test code should not accidentally treat it as true because Python truthiness
works that way.
The useful mental model⚓︎
Think of a Gherkin data table as authored test data, not as ready-to-use Python data. The table is readable for humans first. A table layer gives it shape, types, validation, and diagnostics before the rest of the test uses it.
For the practical workflow, see how to parse a table directly in a step and how to define a row-table contract.
A good table has two readers
The feature author reads the table as product language. The test code reads the parsed result as Python data. Good documentation and good tooling make both readings line up.