Skip to content
Talk to our solutions team

Data-Driven Testing

Run the same test once per row of tabular data. Both runners support this with slightly different syntax.

Declare named data sources at the suite level, reference one from a test:

# suite.yaml (or the test file of a single-file suite)
data:
users:
type: csv
file: fixtures/users.csv # relative to the declaring suite's directory
scopes:
type: inline
rows:
- { name: full, scope: "read write" }
- { name: readonly, scope: "read" }
tests:
- name: get-user
table: users # once per CSV row
steps:
- name: fetch
http:
url: "{{baseurl}}/users/{{id}}"
method: GET
assertions:
- status_code == 200
- response.name == "{{name}}"
typeSourceNotes
inlinerows: — a YAML list of mapsno file needed
yaml / ymlfile:top-level list of maps, or { rows: [...] }
jsonfile:same shapes as yaml
csvfile:first row = header; all values are strings; leading space trimmed; ragged rows are an error
  • file: paths resolve relative to the directory of the suite that declares the source.
  • Lookup walks the suite tree leaf → root, so a parent suite can declare tables for all its descendants.
  • Rows lazy-load on first use and are cached for the run.
  • Each row clones the test; row fields override test.variables (and anything below them in the scope precedence).
  • Per-iteration result names take a suffix from the first present of: _name column → name column → id column → [row=N].
  • Iteration is sequential and stops at the first failed row unless the test sets continue_on_error: true.
  • A table: reference that yields zero rows marks the test errored (an empty fixture is treated as a bug, not a skip).
  • before_each/after_each hooks run around every row.

File-level tables: with per-step (or per-testcase) table: references:

tables:
users:
type: csv
file: users.csv # relative to the suite directory
steps:
- name: get-user-by-id
table: users
rest:
url: "{{baseurl}}/users/{{id}}"
method: GET
  • Table types: csv (optional separator:, default ,) and excel (requires sheet:).
  • File-level tables: propagate automatically to any step/testcase/scenario/testplan in the file that references a table: without declaring its own.
  • Rows show up in the summary as -RC0, -RC1, … suffixes — only when there are ≥ 2 records; single-record runs keep clean names.

The tests runner also takes data on the command line, repeatable and merged in order:

Terminal window
test.svc tests -p tests/data-driven -d env.json -s
test.svc tests -p tests/ -d vars.yaml -d users.csv -s
  • .json / .yaml files merge into the variable map (later files override earlier).
  • .csv files fan out: every row becomes a separate execution record over the merged variables.
  • -v key=value inline vars override everything from -d.
  • Fixture-shaped inputs that belong with the tests → v2 data:/table: (checked in next to the suite, resolved relative to it).
  • Environment-shaped values (URLs, credentials) → env files, not tables (env-file auto-discovery).
  • Quick ad-hoc parameter sweeps with the legacy runner → -d file.csv.