Step Reference
Complete catalogue of every KTestify step. All DataTable columns are listed with their type, whether they are required, the default value (if any), and an inline example.
Background: Given steps
Given namespace
Declares a single namespace prefix applied to all topic names.
Given namespace
| namespace |
| myapp |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
namespace | string | ✅ | none | Namespace prefix (e.g. myapp, com.example) |
Given namespaces
Declares multiple named namespace prefixes.
Given namespaces
| namespace | namespaceAlias |
| myapp.input | input-ns |
| myapp.audit | audit-ns |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
namespace | string | ✅ | none | Namespace prefix |
namespaceAlias | string | ✅ | none | Alias referenced in topic declarations |
Given input topic
Declares one or more Kafka topics as producers (INPUT type).
Given input topic
| topicName | topicAlias | namespace | namespaceAlias |
| orders-in | orders-in | | |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicName | string | ✅ | none | Physical topic name (namespace prepended) |
topicAlias | string | ✅ | none | Alias for use in When steps |
namespace | string | ❌ | Config default | Override namespace for this topic |
namespaceAlias | string | ❌ | none | Reference a Given namespaces alias |
Given output topic
Declares one or more Kafka topics as consumers (OUTPUT type).
Given output topic
| topicName | topicAlias | namespace | namespaceAlias |
| orders-out | enriched | myapp | |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicName | string | ✅ | none | Physical topic name (namespace prepended) |
topicAlias | string | ✅ | none | Alias for use in Then steps |
namespace | string | ❌ | Config default | Override namespace for this topic |
namespaceAlias | string | ❌ | none | Reference a Given namespaces alias |
Given assets directory
Sets the base directory for all relative file paths in the scenario.
Given assets directory
| absolutePath |
| src/test/resources/assets |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
absolutePath | string | ✅ | KTESTIFY_ASSETS_DIR / config | Absolute or project-relative path |
Given schema
Declares an Avro schema for use in Avro producer/consumer steps.
Given schema
| schemaName | schemaAlias | schemaVersion |
| Order | order | 1 |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
schemaName | string | ✅ | none | Schema Registry subject name (prefix for schemaName-value) |
schemaAlias | string | ✅ | none | Short alias |
schemaVersion | integer | ❌ | latest | Schema version to use |
Actions: When steps
Producer and script steps below accept multiple DataTable rows, executed sequentially in order. Producer steps additionally require every row to resolve to the same physical topic (TopicMismatchException otherwise). See Multi-row DataTables for full details.
When record from file is sent
Produces a raw String message to a Kafka input topic.
When record from file is sent
| topicName | file | recordKey | headerFile |
| orders-in | payload.json | key-001 | headers.json |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicName | string | ✅ | none | Topic name or alias (must be declared as INPUT) |
file | string | ✅ | none | Payload file, relative to assets directory |
recordKey | string | ❌ | null | Kafka record key |
headerFile | string | ❌ | none | JSON file of Kafka headers {"name":"value"} |
When record from file based on schema is sent
Produces an Avro-serialised message.
When record from file based on schema is sent
| topicName | file | schemaName | recordKey |
| orders-in | order.json | Order | ord-001 |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicName | string | ✅ | none | Input topic name or alias |
file | string | ✅ | none | JSON payload file |
schemaName | string | ❌ | TopicNameStrategy | Schema alias or name declared via Given schema |
recordKey | string | ❌ | null | Kafka record key |
And wait for {int} seconds
Pauses execution.
And wait for 5 seconds
| Parameter | Type | Required | Description |
|---|---|---|---|
{int} | integer | ✅ | Seconds to pause |
When script is executed / And execute script
Runs a shell script.
When script is executed
| scriptPath | scriptArgs |
| ./scripts/reset.sh | arg1,arg2 |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
scriptPath | string | ✅ | none | Path to the script file |
scriptArgs | string | ❌ | none | Comma-separated arguments |
Fails if exit code ≠ 0.
Assertions: Then / And steps
Every single-record assertion step below (all except the two batch steps) accepts multiple DataTable rows, validated sequentially in order, provided every row targets the same physical topic (TopicMismatchException otherwise). All rows in the same step share one pinned referenceTimestamp so delta-time seek windows don't drift row-to-row. The batch steps (expected records from files / ...based on schema) remain strictly single-row. See Multi-row DataTables → for full details.
Then expected record from file
Raw file match, full value equality.
Then expected record from file
| topicAlias | file | expectedRecordKey | keyMatchStrategy | consumerReadTimeout | consumerDeltaTime |
| orders-out | expected.json | key-001 | exact | 30 | 60 |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicAlias | string | ✅ | none | Output topic alias |
file | string | ✅ | none | Expected file path |
expectedRecordKey | string | ❌ | none | Filter by record key |
keyMatchStrategy | string | ❌ | exact | Key matching strategy: exact, contains, starts_with, ends_with, regex |
consumerReadTimeout | integer | ❌ | Config (30) | Seconds to wait |
consumerDeltaTime | integer | ❌ | Config (60) | Seconds to seek back |
Then expected record should have fields matching from file
Positional character field match.
Then expected record should have fields matching from file
| topicAlias | file | line | from | to |
| orders-out | expected.txt | 2 | 0 | 15 |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicAlias | string | ✅ | none | Output topic alias |
file | string | ✅ | none | Expected file |
line | integer | ✅ | none | 1-based line number |
from | integer | ✅ | none | Start char index (inclusive) |
to | integer | ✅ | none | End char index (exclusive) |
Then expected record from file based on XML
Structural XML comparison with optional element exclusions.
Then expected record from file based on XML
| topicAlias | file | excludedElements | expectedRecordKey | keyMatchStrategy |
| orders-out | expected.xml | ns:CreationDateTime | | |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicAlias | string | ✅ | none | Output topic alias |
file | string | ✅ | none | Expected XML file |
excludedElements | string | ❌ | none | Comma-separated element names to skip |
expectedRecordKey | string | ❌ | none | Filter by record key |
keyMatchStrategy | string | ❌ | exact | Key matching strategy: exact, contains, starts_with, ends_with, regex |
consumerReadTimeout | integer | ❌ | Config (30) | Seconds to wait |
consumerDeltaTime | integer | ❌ | Config (60) | Seconds to seek back |
Then expected record based on XML should have fields matching from file
XPath extraction + comparison.
Then expected record based on XML should have fields matching from file
| topicAlias | file | xpathExpressions |
| orders-out | expected.txt | //Weight[@unit='KG']/text(),//Sender/ID/text() |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicAlias | string | ✅ | none | Output topic alias |
file | string | ✅ | none | Expected values file (one per line) |
xpathExpressions | string | ✅ | none | Comma-separated XPath expressions |
Then expected record from file based on schema
Avro → JSON file match with optional field exclusions.
Then expected record from file based on schema
| topicAlias | file | excludedKeys | expectedRecordKey | keyMatchStrategy | consumerReadTimeout |
| orders-out | expected.json | createdAt,eventId | ord-001 | exact | 30 |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicAlias | string | ✅ | none | Output topic alias |
file | string | ✅ | none | Expected JSON file |
excludedKeys | string | ❌ | none | Comma-separated Avro field names to exclude |
expectedRecordKey | string | ❌ | none | Filter by record key |
keyMatchStrategy | string | ❌ | exact | Key matching strategy: exact, contains, starts_with, ends_with, regex |
consumerReadTimeout | integer | ❌ | Config (30) | Seconds to wait |
consumerDeltaTime | integer | ❌ | Config (60) | Seconds to seek back |
Then expected record based on schema should have fields matching from given value
Assert specific Avro field values without a file.
Single field (use key / value columns):
Then expected record based on schema should have fields matching from given value
| topicAlias | key | value |
| orders-out | status | PROCESSED |
Multiple fields (use keys / values columns, semicolon-separated):
Then expected record based on schema should have fields matching from given value
| topicAlias | keys | values |
| orders-out | status;amount | PENDING;99 |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicAlias | string | ✅ | none | Output topic alias |
key | string | ❌* | none | Avro field name (single-field mode) |
value | string | ❌* | none | Expected field value (single-field mode) |
keys | string | ❌* | none | Semicolon-separated Avro field names (multi-field mode) |
values | string | ❌* | none | Semicolon-separated expected values (multi-field mode) |
consumerReadTimeout | integer | ❌ | Config (30) | Seconds to wait |
consumerDeltaTime | integer | ❌ | Config (60) | Seconds to seek back |
* Either key + value or keys + values must be provided.
Then expected records from files
Raw batch, collect N records and match against N expected files (positionally by default, or in any order when batchMatchStrategy is lazy).
Then expected records from files
| topicAlias | expectedRecordsCount | files | batchMatchStrategy | consumerReadTimeout |
| orders-out | 3 | f1.json,f2.json,f3.json | positional | 60 |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicAlias | string | ✅ | none | Output topic alias |
expectedRecordsCount | integer | ✅ | none | Exact number of records to collect |
files | string | ✅ | none | Comma-separated expected file paths |
batchMatchStrategy | string | ❌ | positional | Batch matching strategy (positional, lazy) |
expectedRecordKeys | string | ❌ | none | Comma-separated expected keys paired 1-to-1 with files (or a single key shared across all records in the batch), filtered during polling and asserted via batchMatchStrategy and keyMatchStrategy |
expectedRecordKey | string | ❌ | none | Single key filter applied while collecting batch records |
keyMatchStrategy | string | ❌ | exact | Key matching strategy (exact, contains, starts_with, ends_with, regex) |
consumerReadTimeout | integer | ❌ | Config (30) | Seconds to wait for all records |
consumerDeltaTime | integer | ❌ | Config (60) | Seconds to seek back |
Then expected records from files based on schema
Avro batch, collect N Avro records and match against N expected files (positionally by default, or in any order when batchMatchStrategy is lazy).
Then expected records from files based on schema
| topicAlias | expectedRecordsCount | files | excludedKeys | batchMatchStrategy | consumerReadTimeout |
| orders-out | 2 | exp-1.json,exp-2.json | ts,eventId | lazy | 60 |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicAlias | string | ✅ | none | Output topic alias |
expectedRecordsCount | integer | ✅ | none | Exact number of records to collect |
files | string | ✅ | none | Comma-separated expected JSON file paths |
excludedKeys | string | ❌ | none | Avro field names to exclude from all records |
batchMatchStrategy | string | ❌ | positional | Batch matching strategy (positional, lazy) |
expectedRecordKeys | string | ❌ | none | Comma-separated expected keys paired 1-to-1 with files (or a single key shared across all records in the batch), filtered during polling and asserted via batchMatchStrategy and keyMatchStrategy |
expectedRecordKey | string | ❌ | none | Single key filter applied while collecting batch records |
keyMatchStrategy | string | ❌ | exact | Key matching strategy (exact, contains, starts_with, ends_with, regex) |
consumerReadTimeout | integer | ❌ | Config (30) | Seconds to wait for all records |
consumerDeltaTime | integer | ❌ | Config (60) | Seconds to seek back |
And record should appear in topic
Positive watcher, asserts at least one record is present.
And record should appear in topic
| topicAlias | topicType | expectedRecordKey | keyMatchStrategy | consumerReadTimeout | consumerDeltaTime |
| orders-out | raw | order- | starts_with | 15 | 60 |
| Column | Type | Required | Default | Description |
|---|---|---|---|---|
topicAlias | string | ✅ | none | Output topic alias |
topicType | string | ✅ | none | raw or avro |
expectedRecordKey | string | ❌ | none | Filter by record key |
keyMatchStrategy | string | ❌ | exact | Key matching strategy: exact, contains, starts_with, ends_with, regex |
consumerReadTimeout | integer | ❌ | Config (30) | Seconds to wait |
consumerDeltaTime | integer | ❌ | Config (60) | Seconds to seek back |
And record should not appear in topic
Negative watcher, asserts no record appears within the timeout.
And record should not appear in topic
| topicAlias | topicType | expectedRecordKey | keyMatchStrategy | consumerReadTimeout | consumerDeltaTime |
| orders-out | raw | non-existent | exact | 10 | 30 |
Same columns as record should appear in topic.
Matcher × Topic type compatibility
| Matcher step | raw topics | avro topics |
|---|---|---|
expected record from file | ✅ | ❌ use based on schema |
expected record from file based on XML | ✅ | ❌ not available |
expected record based on XML / XPath | ✅ | ❌ not available |
expected record from file based on schema | ❌ | ✅ |
expected record based on schema / field value | ❌ | ✅ |
expected records from files (batch) | ✅ | ❌ |
expected records from files based on schema (batch) | ❌ | ✅ |
record should (not) appear in topic | ✅ both | ✅ both |
Key matching strategies
When a step includes an expectedRecordKey column, you can optionally specify a keyMatchStrategy column to control how the expected key is matched against the actual record key. This is useful when record keys are dynamically generated (UUIDs, prefixed keys, timestamps) and an exact match is too restrictive.
| Strategy | DataTable value | Behaviour | Example |
|---|---|---|---|
EXACT | exact | Exact string equality (default) | "order-001" matches "order-001" |
CONTAINS | contains | Expected key is a substring of the actual key | "order" matches "order-001" |
STARTS_WITH | starts_with | Actual key starts with the expected key | "order-" matches "order-001" |
ENDS_WITH | ends_with | Actual key ends with the expected key | "001" matches "order-001" |
REGEX | regex | Actual key matches the expected Java regex pattern | "order-\\d+" matches "order-001" |
The keyMatchStrategy value is case-insensitive and tolerant of hyphens, underscores, and spaces. For example, starts_with, starts-with, starts_with, StartsWith, and starts with all resolve to STARTS_WITH. Unrecognised values default to EXACT.
When using non-exact strategies (contains, regex, starts_with), ensure your match pattern is specific enough to uniquely identify the intended record. Kafka topics may contain records from prior scenarios in the same feature file, and a broad pattern (e.g. contains "key") may match a decoy record first, causing value mismatches.
Example: matching a UUID-prefixed key
# Record key is "550e8400-e29b-41d4-a716-446655440000"
Then expected record from file
| topicAlias | file | expectedRecordKey | keyMatchStrategy | consumerReadTimeout |
| orders-out | expected.json | 550e8400 | starts_with | 30 |
Example: matching a dynamic key with regex
# Record key is "ORD-2026-000001"
Then expected record from file
| topicAlias | file | expectedRecordKey | keyMatchStrategy | consumerReadTimeout |
| orders-out | expected.json | ORD-\d{4}-\d{6} | regex | 30 |
Batch matching strategies
In batch assertion steps (Then expected records from files and Then expected records from files based on schema), the optional batchMatchStrategy column controls how collected records are compared against the comma-separated list of expected files:
| Strategy | Accepted DataTable values | Behaviour |
|---|---|---|
POSITIONAL | positional, ordered, index, strict | Default. Record at index i must match file at index i (and expectedRecordKeys[i] when set). |
LAZY | lazy, fuzzy, unordered, any_order, any-order | Order-independent 1-to-1 matching without replacement. Each consumed record claims the first unmatched expected file (and corresponding expectedRecordKeys[j] when set) whose content and key match. |
The batchMatchStrategy value is case-insensitive and normalizes hyphens and spaces to underscores. Unrecognised or blank values default to POSITIONAL.
Then expected records from files
| topicAlias | expectedRecordsCount | files | batchMatchStrategy | consumerReadTimeout |
| orders-out | 3 | f1.json,f2.json,f3.json | lazy | 30 |