Data-Driven Testing, Templates, Embedded Arguments, and Variants: Guided Hands-On Workflow
Refactor duplicated synthetic validation cases into named template variants, add a negative row, use embedded arguments for readable calls, compare the same matrix with a FOR loop, and inspect result identity and failure evidence.
Learning objectives
- Convert duplicated tests into a suite-level Test Template while preserving descriptive test names.
- Add positive, boundary, and negative variants with explicit expected classifications.
- Use one embedded-argument template safely and understand the generated keyword call name.
- Compare template variants with separate explicit tests and a FOR-loop implementation.
- Inspect output.xml/log/report evidence and identify the smallest diagnosable rerun unit.
Current compatibility baseline. Verified 2026-08-31: Robot Framework 7.4.2 is the current stable release and requires Python 3.8+; 7.5b1 is a pre-release and is not required in this chapter. In 7.4.2, templates can use normal, named, and embedded arguments. A templated test containing multiple data rows executes all rows even when one fails or is skipped, then aggregates the test status. User-keyword argument type conversion is stable from Robot Framework 7.3.
1. Disposable scenario: identifier classification
The system under automation is deliberately synthetic. An identifier is accepted when its length is between 3 and 8 characters inclusive and every character is ASCII alphanumeric. There is no network, browser, database, file mutation, or paid service. The only persistent evidence is Robot Framework output under a chosen result directory.
2. Preflight and project layout
rf11-data-lab/
└── suites/
└── identifiers.robot
python --version
python -m robot --version
python -m robot --dryrun --outputdir results/dryrun suites/identifiers.robot
For this course baseline, record Robot Framework 7.4.2 and the actual Python version in your evidence notes. The suite uses only BuiltIn.
3. Start with the duplication so the refactor has a reason
*** Test Cases ***
Minimum valid
${actual}= Classify Identifier abc
Should Be Equal ${actual} ACCEPT
Too short
${actual}= Classify Identifier ab
Should Be Equal ${actual} REJECT
Contains punctuation
${actual}= Classify Identifier ab-c
Should Be Equal ${actual} REJECT
The tests are clear but each repeats the same two-step contract. As the matrix grows, a message change or classifier refactor must be repeated in every test.
4. Refactor to a suite-level Test Template
*** Settings ***
Test Template Identifier Should Have Classification
*** Test Cases *** CANDIDATE EXPECTED
Minimum valid abc ACCEPT
Maximum valid abc12345 ACCEPT
Too short ab REJECT
Too long abc123456 REJECT
Contains punctuation ab-c REJECT
*** Keywords ***
Identifier Should Have Classification
[Arguments] ${candidate} ${expected}
${actual}= Classify Identifier ${candidate}
Should Be Equal ${actual} ${expected}
... msg=classification mismatch for candidate=${candidate}
Classify Identifier
[Arguments] ${candidate}
${length}= Get Length ${candidate}
IF $length < 3 or $length > 8
RETURN REJECT
END
${alnum}= Run Keyword And Return Status
... Should Match Regexp ${candidate} ^[A-Za-z0-9]+$
IF not $alnum
RETURN REJECT
END
RETURN ACCEPT
Run Keyword And Return Status is used narrowly here to
classify whether a pattern matches. The final test contract is still
a hard Should Be Equal; a wrong classification fails
the test. This is not a pattern for turning arbitrary test failures
into green booleans.
5. Execute and inspect the named variants
python -m robot --outputdir results/named suites/identifiers.robot
Expected result: five tests and five PASS statuses. The negative
variants pass because the classifier returns REJECT and
the expected column also says REJECT. No expected-error
suppression is involved.
| Evidence | What to verify |
|---|---|
| Console | Five tests executed; suite PASS |
| report.html | Five separately named tests such as “Too short” |
| log.html | Each test contains one template keyword call and classifier trace |
| output.xml | Five test elements, each with its own name/status |
6. Make the template call itself readable with embedded arguments
Replace the template contract with an embedded-argument keyword. The source test names stay the same; the log call now contains the concrete candidate and expected classification:
*** Settings ***
Test Template Identifier "${candidate}" should be ${expected}
*** Test Cases *** CANDIDATE EXPECTED
Minimum valid abc ACCEPT
Contains punctuation ab-c REJECT
*** Keywords ***
Identifier "${candidate}" should be ${expected}
${actual}= Classify Identifier ${candidate}
Should Be Equal ${actual} ${expected}
Quoting ${candidate} gives the embedded argument a
visible boundary. This matters if later values contain spaces.
7. Inject one wrong expectation and preserve the evidence
Change only one row temporarily:
Contains punctuation ab-c ACCEPT
python -m robot --outputdir results/intentional-fail suites/identifiers.robot
Expected command exit status is non-zero. Preserve
results/intentional-fail. The failure message should
include candidate=ab-c (if using the normal template
version) or the embedded call name. Repair the expected value to
REJECT only after you have captured the first-failure
artifacts.
8. Compare with one multi-row templated test
*** Test Cases ***
Grouped identifier matrix
[Template] Identifier Should Have Classification
abc ACCEPT
ab ACCEPT
ab-c REJECT
abc12345 ACCEPT
The intentionally wrong ab / ACCEPT row fails, but
Robot still runs the later rows. The report contains one failing
test named Grouped identifier matrix. The log contains
all template iterations. This is compact, but the rerun unit is the
whole grouped test.
9. Compare with a FOR loop
*** Test Cases ***
Loop over identifier matrix
FOR ${candidate} ${expected} IN
... abc ACCEPT
... ab REJECT
... ab-c REJECT
${actual}= Classify Identifier ${candidate}
Should Be Equal ${actual} ${expected}
END
This is one test and one loop. Unlike a template’s automatic iteration continuation, a normal failing assertion stops this test unless you explicitly add other failure-control behavior. A FOR loop is appropriate when the iteration itself is one business behavior; it is weaker when each row deserves separate release/rerun identity.
10. Same data, different operational meaning
| Shape | Report test count | Failure/rerun unit | Use when |
|---|---|---|---|
| Separate explicit tests | One per variant | Variant | Workflows differ or names/steps matter independently |
| Suite-level Test Template | One per named variant | Variant | Same contract; strong CI identity |
| One test + multiple template rows | One | Whole grouped test | Rows belong to one test lifecycle and aggregate evidence is acceptable |
| One test + FOR | One | Whole loop test | Iteration is an implementation detail of one scenario |
11. Challenge: choose the layer before changing syntax
You need to validate 12 release labels. Six are boundaries that the release team tracks independently; the other six are diagnostic samples used only to exercise one parsing behavior. Decide which belong as separate named templated tests and which could be grouped. Write a one-paragraph rationale based on rerun identity, setup isolation, and report readability—not line-count reduction.
12. Knowledge check
Why does a negative row such as “Too short → REJECT” still produce a PASS test?
The test contract is that the classifier output equals the expected classification. REJECT is valid expected output for that input; no failure is being suppressed.
If one grouped template row fails, what should happen to later template rows?
They still execute under Robot Framework 7.4.2 template continuation semantics, and the aggregate test becomes FAIL.
Which shape gives each variant its own report/rerun identity while still removing workflow duplication?
Separate named tests under a suite-level Test Template.
Why is a FOR loop not automatically equivalent to a multi-row template?
It is one normal test loop and does not automatically use the template continuation semantics; it also expresses iteration as procedural control rather than declarative variant data.
13. Summary and next step
You have converted repeated behavior into an explicit template contract without giving up variant names, compared embedded calls, grouped iterations, and loops, and preserved a deliberate failure as evidence. Lesson 3 turns these mechanics into design rules for matrix size, typed data, external data boundaries, and abstraction choice.
Further reading
- Robot Framework 7.4.2 User Guide — Test templates — basic templates, multiple iterations, embedded arguments, FOR, and IF/ELSE.
- Robot Framework 7.4.2 User Guide — Different test case styles — keyword-driven, data-driven, and BDD-style presentation.
- Robot Framework 7.4.2 User Guide — Embedded arguments — matching rules, ambiguity, and custom regular expressions.
- Robot Framework 7.4.2 User Guide — User-keyword argument conversion — typed user keyword arguments available from 7.3.
- Robot Framework 7.4.2 on PyPI — pinned stable package metadata and Python requirement.
- Robot Framework releases — re-check stable and pre-release status when updating the course.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.