Checkpoint Lab — Data-Driven Testing, Templates, Embedded Arguments, and Variants
Build a compact data-driven build-ID validation suite with boundary and negative variants, prove each report entry is diagnosable, deliberately add a redundant environment dimension, and reduce it with a documented risk rationale.
Learning objectives
- Create a deterministic local validation rule and represent it with separately named templated variants.
- Include boundary, positive, and negative cases without using expected-error suppression.
- Predict report/test identity and failure behavior before execution, then verify it independently.
- Inject one wrong expectation and preserve the resulting first-failure packet.
- Add and then remove a redundant matrix dimension using a documented causal/risk argument.
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. Checkpoint charter and safety boundary
Validate synthetic build IDs only. The rule accepts exactly
AA-000 style identifiers: two uppercase ASCII letters,
one dash, and three digits. No external system is contacted. No
files are mutated except Robot Framework result artifacts in the
chosen output directories. Use only fake data.
Evidence-first rule. One run is intentionally made to fail by changing an expected classification. Do not delete or overwrite that result directory after repair.
2. Predict the state/result changes
flowchart TD A[Named build-ID variant] --> B[Test Template] B --> C[Build ID value + expected class] C --> D[Classifier keyword] D --> E[ACCEPT / REJECT] E --> F[Hard assertion] F --> G[Per-test PASS / FAIL] G --> H[results/<run>/output.xml + log.html + report.html]
| Prediction | Before run | How to verify |
|---|---|---|
| Each named row becomes one test | 6 named tests | Report and output.xml test count |
| Negative data is not a Robot failure by itself | REJECT rows can PASS | Expected/actual classification match |
| Wrong expectation fails one named test | Non-zero process exit | Failure message + report row |
| Adding environment values does not change classifier output | Environment is non-causal | Same result across synthetic env labels |
3. Implement the compact suite
*** Settings ***
Test Template Build ID "${build_id}" should be ${expected}
*** Test Cases *** BUILD_ID EXPECTED
Nominal valid AB-123 ACCEPT
Lower numeric boundary AB-000 ACCEPT
Upper numeric boundary ZZ-999 ACCEPT
Lowercase rejected ab-123 REJECT
Missing dash rejected AB123 REJECT
Wrong digit count rejected AB-12 REJECT
*** Keywords ***
Build ID "${build_id}" should be ${expected}
${actual}= Classify Build ID ${build_id}
Should Be Equal ${actual} ${expected}
... msg=build-id classification mismatch for ${build_id}
Classify Build ID
[Arguments] ${build_id}
${matches}= Run Keyword And Return Status
... Should Match Regexp ${build_id} ^[A-Z]{2}-[0-9]{3}$
IF $matches
RETURN ACCEPT
END
RETURN REJECT
The classifier converts a pattern-match outcome into a domain
classification. The test then performs the hard assertion. Thus a
negative input such as ab-123 passes only when it is
classified as REJECT.
4. Preflight
python --version
python -m robot --version
python -m robot --dryrun --outputdir evidence/dryrun suites/build_ids.robot
Record the exact interpreter/framework versions and the source revision/checksum in your evidence notes.
5. Run the clean baseline
python -m robot --outputdir evidence/baseline suites/build_ids.robot
Expected: six tests, all PASS, zero exit status. Open
report.html and verify that every business variant is a
separately named test rather than one anonymous grouped matrix.
6. Inject one reversible failure
Change only this row:
Lowercase rejected ab-123 ACCEPT
python -m robot --outputdir evidence/injected-failure suites/build_ids.robot
Expected: the command exits non-zero and the test
Lowercase rejected fails. The failure message must
include ab-123. Restore the row to REJECT,
but keep evidence/injected-failure unchanged.
7. Verify the repair independently
python -m robot --test "Lowercase rejected" --outputdir evidence/repaired suites/build_ids.robot
Expected: one selected test and PASS. Compare the injected and repaired logs rather than overwriting the original failure.
8. Deliberately create a redundant environment dimension
The classifier never reads an environment. To demonstrate matrix
explosion, imagine multiplying each of the six rows by
dev, stage, and prod. That
produces 18 tests with no new classifier code path.
| Original risk case | dev | stage | prod | New behavioral information? |
|---|---|---|---|---|
| Nominal valid | same | same | same | No |
| Lowercase rejected | same | same | same | No |
| Missing dash rejected | same | same | same | No |
If you want to demonstrate the redundancy in source, temporarily add
an ${environment} argument that is only logged and
never used by the classifier. Run it once, then remove the
dimension. The final project should not keep a non-causal 3×
multiplier.
9. Write the risk-based reduction rationale
Your final note should say:
The build-ID classifier is a pure local rule whose inputs are only the build-ID characters. Deployment environment is not read by the classifier and does not alter its output. Therefore environment is not multiplied across syntax-boundary variants. Environment wiring belongs in a separate integration contract if/when the system behavior actually differs by environment.
This is stronger than “we reduced tests to save time” because it identifies the causal boundary.
10. Required evidence packet
- Python and Robot Framework version output.
-
Exact
--dryrun, baseline, injected-failure, and repaired commands. - The final six-row template source.
-
Baseline
output.xml,log.html, andreport.html. -
Injected-failure artifacts showing the named row and concrete
ab-123context. - Repaired single-test artifacts.
- A table or note showing 6 × 3 = 18 redundant environment combinations.
- The written causal/risk reduction rationale.
11. Verification checklist
- Exactly six final named variants exist.
- Every REJECT row passes because classification equals expected output, not because an error was swallowed.
- No real credentials, PII, production URLs, or generated random values are present.
- The injected-failure directory remains intact after repair.
- The final suite does not include the redundant environment multiplier.
-
report.htmlgives each final variant an independently understandable name. - The suite uses Robot Framework core/BuiltIn only.
12. Cleanup / rollback
No system-under-test state exists to clean. If you want to remove
lab evidence, first archive the evidence packet required by your
learning/CI policy, then delete only the local
evidence/ directory you created for this lab. Do not
use recursive deletion commands against an unverified path.
13. What this adds to a production operating model
Chapter 11 adds a governance rule for variation: one template contract, explicit risk-significant data, stable variant names, deterministic provenance, and result identity that matches the rerun/ownership need. It also establishes that matrix size is an architecture decision—not a badge of coverage.
14. Knowledge check
Why does “Lowercase rejected → REJECT” pass without hiding a failure?
The classifier returns a domain value and the test asserts that value. The negative input is expected data, not an expected Robot execution failure.
What evidence proves the injected failure is attributable?
The separately named test, concrete build ID in the failure message/log, preserved output.xml/log/report, and the exact source row/command.
Why is environment removed from the final matrix?
The classifier does not read environment, so the dimension is non-causal and triples runtime without exercising a new behavior path.
If each environment later changes the rule, what should happen?
Environment becomes causal. Add explicit environment-specific contract coverage—possibly separate tests/templates—rather than relying on the old reduction rationale.
What does Chapter 12 add next?
Resource files, variable files, library imports, and project layout—how to move reusable code/data into explicit project boundaries without losing import/provenance clarity.
15. Checkpoint complete
You can now create compact data-driven suites without sacrificing diagnosability: variant names remain meaningful, negative inputs use explicit output contracts, failures preserve row context, and redundant dimensions are removed with a causal risk rationale. Chapter 12 moves from variant design to reusable project organization and import boundaries.
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.