Checkpoint Lab — Keywords, Arguments, Return Values, and Reusable Abstractions
Refactor a flat synthetic suite into layered domain and utility keywords, prove behavior equivalence, inject a low-level failure, and leave an evidence packet showing that the high-level log still exposes the failing contract.
Checkpoint objectives
- Start from a known flat suite and record baseline PASS/FAIL behavior plus low-level call evidence.
- Refactor the same behavior into high-level domain keywords and low-level utility keywords with explicit arguments and return values.
- Prove the refactor does not change the intended outputs or test outcomes.
- Inject one low-level failure without swallowing it and diagnose it from the high-level call hierarchy.
- Produce a reusable keyword-interface convention and evidence packet suitable for code review and CI handoff.
Checkpoint safety boundary. Robot Framework 7.4.2,
Python 3.12.x, BuiltIn + standard String only. All
source, result artifacts, and failure injection stay inside a
disposable rf-keyword-checkpoint directory. No external
services, credentials, production data, paid tools, Pabot workers,
containers, or CI runners are required.
1. Scenario: synthetic candidate labels with positive and negative validation
A release-quality team has a flat suite that builds synthetic candidate labels. It currently duplicates normalization and label construction. Your job is to refactor it into a readable domain layer while retaining enough nested technical evidence for diagnosis.
The checkpoint has two normal cases and one deliberately injected failing case. The failure must remain a real FAIL; do not turn it into data or retry it away.
2. Preflight and disposable project tree
python --version
python -m robot --version
mkdir rf-keyword-checkpoint
cd rf-keyword-checkpoint
Create this local structure:
rf-keyword-checkpoint/
├── flat.robot
├── refactored.robot
├── broken.robot
├── evidence/
│ ├── flat/
│ ├── refactored/
│ └── broken/
└── decisions/
└── keyword-convention.md
Before writing code, record the absolute checkpoint path and confirm it is a disposable training directory. This is the only mutable filesystem scope.
3. Prediction sheet: state and evidence before execution
Write these predictions in
decisions/predictions.md before running anything:
| Question | Prediction to record |
|---|---|
| What changes during the flat run? | Only local Robot variables and result artifacts; no external state. |
| What should stay identical after refactor? | Final labels, assertion outcomes, test names, and suite intent. |
| What should change after refactor? |
Call hierarchy: domain/utility user-keyword nodes appear in
log.html.
|
| Who owns raw candidate/component inputs? | The test/caller. |
| Who owns normalized intermediate values? | The utility/domain keyword call frame unless explicitly returned. |
| Who owns final label output? | The caller after RETURN. |
| What should happen after injected low-level mismatch? | Nested assertion fails; domain keyword and test fail; first-failure log remains visible. |
4. Build and run the flat baseline
Create flat.robot:
*** Settings ***
Library String
*** Test Cases ***
API Candidate Label
${raw}= Set Variable API Candidate 42
${lower}= Convert To Lower Case ${raw}
${slug}= Replace String ${lower} ${SPACE} -
${label}= Catenate SEPARATOR=: qa api ${slug}
Should Be Equal ${label} qa:api:api-candidate-42
UI Candidate Label
${raw}= Set Variable UI Candidate 42
${lower}= Convert To Lower Case ${raw}
${slug}= Replace String ${lower} ${SPACE} -
${label}= Catenate SEPARATOR=: qa ui ${slug}
Should Be Equal ${label} qa:ui:ui-candidate-42
python -m robot --outputdir evidence/flat flat.robot
Expected: two PASS tests. Preserve
evidence/flat/output.xml, log.html, and
report.html.
5. Refactor into domain and utility keyword layers
Create refactored.robot. The
domain keyword expresses scenario intent; the
utility keyword owns technical normalization. The
caller still owns scenario inputs and final assertion.
*** Settings ***
Library String
*** Test Cases ***
API Candidate Label
${label}= Build Candidate Label api API Candidate 42 environment=qa
Should Be Equal ${label} qa:api:api-candidate-42
UI Candidate Label
${label}= Build Candidate Label ui UI Candidate 42 environment=qa
Should Be Equal ${label} qa:ui:ui-candidate-42
*** Keywords ***
Build Candidate Label
[Arguments] ${component} ${raw_candidate} @{} ${environment}=local
${slug}= Normalize Candidate Id ${raw_candidate}
${label}= Catenate SEPARATOR=: ${environment} ${component} ${slug}
RETURN ${label}
Normalize Candidate Id
[Arguments] ${raw_candidate}
${lower}= Convert To Lower Case ${raw_candidate}
${slug}= Replace String ${lower} ${SPACE} -
RETURN ${slug}
python -m robot --outputdir evidence/refactored refactored.robot
Expected: the same two PASS outcomes and the same final labels. The
new log should show Build Candidate Label →
Normalize Candidate Id → String-library calls.
6. Prove behavior equivalence instead of assuming it
Complete this evidence table from the two runs:
| Observation | Flat | Refactored | Expected conclusion |
|---|---|---|---|
| API final label | qa:api:api-candidate-42 | same | Behavior preserved. |
| UI final label | qa:ui:ui-candidate-42 | same | Behavior preserved. |
| Test status | PASS/PASS | PASS/PASS | No semantic regression. |
| Test names | same | same | Suite identity preserved. |
| Low-level String calls | Direct under test | Nested under utilities | Implementation is reusable but still visible. |
| Data flow | Copied intermediates | Explicit args + return | Ownership improved. |
If any final output/status changes, stop and fix the refactor before injecting a failure.
7. Capture keyword signature evidence
python -m robot.libdoc refactored.robot list
python -m robot.libdoc refactored.robot show "Build Candidate Label"
python -m robot.libdoc refactored.robot evidence/refactored-keywords.html
Verify that component and
raw_candidate are normal required arguments and
environment is named-only with default
local. Record the output or screenshot in the evidence
packet.
8. Inject a low-level failure without hiding it
Copy the refactored file to broken.robot. Add one
deliberate assertion inside Normalize Candidate Id that
requires the normalized slug to begin with api-. This
makes the UI case fail at the utility level while the API case still
passes.
Normalize Candidate Id
[Arguments] ${raw_candidate}
${lower}= Convert To Lower Case ${raw_candidate}
${slug}= Replace String ${lower} ${SPACE} -
Should Start With ${slug} api-
RETURN ${slug}
Should Start With belongs to the imported String
library. Do not catch or ignore its failure.
python -m robot --outputdir evidence/broken broken.robot
Expected: API Candidate Label PASS, UI Candidate Label FAIL. The command should return a non-zero exit status because at least one test failed.
9. Diagnose from the high-level log down to the failing contract
Open evidence/broken/log.html and follow the failing
tree:
- UI Candidate Label — scenario intent failed.
- Build Candidate Label — domain capability failed while delegating normalization.
- Normalize Candidate Id — utility contract failed.
-
String.Should Start With — the concrete assertion
explains that
ui-candidate-42does not start withapi-.
This is the desired diagnostic property: abstraction improved readability without erasing the primitive failure.
Do not “repair” the checkpoint by adding
Run Keyword And Ignore Error, a retry, or a generic
default return.
The injected mismatch is evidence that the utility contract is
wrong for the UI caller.
10. Repair the contract, not the symptom
The low-level assertion encoded an API-only rule inside a generic
normalization utility. The correct repair is to remove that
assertion from Normalize Candidate Id and, if the API
scenario truly requires an API prefix, assert that requirement at
the domain/test layer that owns it.
Re-run the repaired suite into evidence/repaired if you
want a third comparison. Preserve
evidence/broken unchanged.
11. Write the keyword-interface convention
Create decisions/keyword-convention.md containing at
least these rules:
- High-level keywords express domain/operational intent; utilities express technical transformations.
- Callers own scenario choices; signatures expose those choices explicitly.
- Use defaults only for stable, safe project policy.
- Use named-only arguments for options whose unlabeled positional form would be ambiguous.
-
Use
RETURNfor normal data flow; avoid suite/global mutation as helper output. - Keep return shapes stable and documented.
- Do not hide failures; preserve nested context in logs.
- Qualify or rename ambiguous keyword owners; do not rely on guesswork.
- Wrap libraries only when the wrapper adds project policy/meaning.
- Keyword names must reveal meaningful side effects.
12. Assemble the checkpoint evidence packet
- Python and Robot Framework version output;
-
flat.robot,refactored.robot, andbroken.robot; - prediction sheet;
- flat/refactored/broken execution commands and exit statuses;
-
three sets of
output.xml/log.html/report.html; - Libdoc signature evidence;
- behavior-equivalence table;
- failure-path notes showing test → domain → utility → String assertion;
keyword-convention.md.
Everything is synthetic, but inspect artifacts before sharing them. In real projects, arguments, messages, screenshots, and result XML may contain sensitive data.
13. Verification checklist
- Exactly two baseline tests PASS in both flat and refactored runs.
- Final labels are byte-for-byte equivalent across the baseline/refactored runs.
- The refactored log contains both domain and utility user-keyword nodes.
- No suite/global variable is used for ordinary data flow.
- Libdoc shows the intended required/named-only/default signature.
- The injected UI failure remains FAIL and causes a non-zero Robot exit status.
- The broken log exposes the failing String assertion under the correct higher-level call chain.
- The broken result artifacts are preserved after repair.
- No real secrets, production URLs, personal data, external accounts, or uncontrolled systems were used.
14. Cleanup and rollback
The lab creates only the local checkpoint directory and result
artifacts. If you keep it, it becomes useful input for Chapter 06
variable-scope discussion. If deleting it, move to its parent
directory, print/inspect the target, and remove only
rf-keyword-checkpoint. There is no external rollback
because no external service was mutated.
15. Knowledge check
Why is matching final output/status across flat and refactored runs stronger evidence than saying the code “looks equivalent”?
It verifies the observable behavior while the internal call hierarchy changes. Refactoring is about preserving behavior, not appearance.
Why did the injected UI failure belong outside the generic normalization utility?
The api- prefix is API-domain policy, not a
universal normalization rule. Putting it in the utility made the
abstraction semantically wrong for UI callers.
What evidence proves that abstraction did not destroy diagnostics?
The broken log shows the high-level test and domain keyword, then the utility keyword, then the exact failing String assertion/message.
Why is environment named-only in the checkpoint
design?
It is an optional policy choice whose unlabeled positional value would be ambiguous at the call site.
What should Chapter 06 add to this operating model?
A precise model of scalar/list/dictionary/environment/dynamic variables and their scopes, building on the local-vs-shared data ownership rules established here.
16. Production operating model and bridge to Chapter 06
Chapter 05 adds a reusable-interface layer to the Robot Framework operating model: clear keyword ownership, deliberate resolution, explicit argument contracts, stable return shapes, local data flow, honest side-effect names, shallow meaningful composition, and failure evidence that remains intact through abstraction.
Chapter 06 now examines the data carried through those interfaces: scalar, list, dictionary, environment, and dynamic variables; scope/lifetime; precedence; and the difference between explicit local values and shared mutable state.
Further reading
- Robot Framework 7.4.2 User Guide — Creating user keywords — keyword syntax, arguments, embedded arguments, return values, setup/teardown, privacy, and recursion.
- Robot Framework 7.4.2 User Guide — Handling keywords with same names — resolution scope, explicit qualification, and search order.
- Robot Framework 7.4.2 User Guide — Libdoc — generating user/library documentation and inspecting keyword signatures.
- RFCP syllabus — User Keyword Definition & Arguments — keyword naming, interfaces, arguments, and maintainable design.
- Robot Framework Style Guide — naming, abstraction level, keyword design, and maintainability guidance.
- Robot Framework 7.4.2 release notes — current stable-line changes and deprecations.
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.