Checkpoint Lab — Setups, Teardowns, Tags, Timeouts, and Suite Lifecycle
Build a lifecycle matrix with passing, failing, timed-out, and setup-failed disposable tests; predict exact order, prove it from logs/filesystem evidence, then refactor shared mutable state into deterministic per-test ownership.
Learning objectives
- Predict and verify setup/body/teardown order for PASS, body FAIL, setup FAIL, and TIMEOUT cases.
- Demonstrate that teardown runs after body/setup failure and after test timeout.
- Compare tag include/skip/exclude behavior using preserved result artifacts.
- Detect an order-dependent shared-state fixture and refactor it to per-test isolation.
- Produce a production-style lifecycle convention and evidence packet with safe cleanup.
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
here. Suite, test/task, and user-keyword setups/teardowns are
supported; user-keyword [Setup] was added in Robot
Framework 7.0. Test Tags is the modern suite-level tag
setting, while Force Tags/Default Tags are
deprecated. Test timeouts and user-keyword timeouts have different
cleanup behavior, which this chapter treats explicitly.
1. Checkpoint charter
Create a self-contained lifecycle lab under a disposable directory. No network, browser, API, database, SSH, container, or paid tool is required. The suite creates only guarded temp state and Robot output evidence. You will run each failure class separately so evidence remains attributable.
Do not normalize failures away. PASS, FAIL, setup FAIL, and TIMEOUT are intentional outcomes. The checkpoint succeeds when you can predict and explain them, not when every Robot command exits zero.
2. Predict the lifecycle matrix before running
| Case | Suite setup | Test setup | Body | Test teardown | Suite teardown | Expected status |
|---|---|---|---|---|---|---|
| Pass | Yes | PASS | Runs fully | Runs | Runs | PASS |
| Body fail | Yes | PASS | Stops at Fail | Runs | Runs | FAIL |
| Setup fail | Yes | FAIL | Does not run | Runs | Runs | FAIL |
| Timeout | Yes | PASS | Interrupted at timeout | Runs | Runs | FAIL |
3. Implement the lifecycle matrix suite
*** Settings ***
Library OperatingSystem
Suite Setup Suite Start
Suite Teardown Suite End
Test Setup Case Start
Test Teardown Case End
Test Tags rf09 checkpoint
*** Variables ***
${RUN_ID} checkpoint-001
${ROOT} ${TEMPDIR}/rf09-checkpoint-${RUN_ID}
${TRACE} ${OUTPUT DIR}/trace.txt
${SUITE_OWNS_ROOT} ${False}
*** Test Cases ***
Case Passes
[Tags] case-pass
Trace ${TEST NAME}|body-start
File Should Exist ${CASE_FILE}
Trace ${TEST NAME}|body-end
Case Body Fails
[Tags] case-body-fail
Trace ${TEST NAME}|body-start
Fail checkpoint-primary-failure
Trace ${TEST NAME}|unreachable
Case Setup Fails
[Tags] case-setup-fail
[Setup] Failing Case Start
Trace ${TEST NAME}|unreachable-body
Case Times Out
[Tags] case-timeout
[Timeout] 250 milliseconds
Trace ${TEST NAME}|body-start
Sleep 2 seconds
Trace ${TEST NAME}|unreachable
*** Keywords ***
Suite Start
Guard Root
Directory Should Not Exist ${ROOT}
Create Directory ${ROOT}
Set Suite Variable ${SUITE_OWNS_ROOT} ${True}
Create File ${TRACE} suite-setup\n
Case Start
Create Owned Case File
Trace ${TEST NAME}|test-setup
Failing Case Start
Create Owned Case File
Trace ${TEST NAME}|test-setup-before-fail
Fail checkpoint-setup-failure
Create Owned Case File
${safe}= Evaluate re.sub(r'[^A-Za-z0-9_.-]+', '_', $TEST_NAME) modules=re
${case}= Join Path ${ROOT} ${safe}.txt
Set Test Variable ${CASE_FILE} ${case}
Create File ${CASE_FILE} owner=${TEST NAME}\n
Case End
Trace ${TEST NAME}|test-teardown-start
${status} ${message}= Run Keyword And Ignore Error Remove File ${CASE_FILE}
Trace ${TEST NAME}|remove-status=${status}
File Should Not Exist ${CASE_FILE}
Trace ${TEST NAME}|test-teardown-end
Suite End
Trace suite-teardown-start
IF ${SUITE_OWNS_ROOT}
Guard Root
Remove Directory ${ROOT} recursive=True
Directory Should Not Exist ${ROOT}
ELSE
Log Root was not created by this suite; leaving it untouched.
END
Trace suite-teardown-end
Guard Root
${candidate}= Normalize Path ${ROOT} case_normalize=True
${temp}= Normalize Path ${TEMPDIR} case_normalize=True
Should Start With ${candidate} ${temp}${/}
Should Contain ${candidate} rf09-checkpoint-
Trace
[Arguments] ${message}
Append To File ${TRACE} ${message}\n ... encoding=UTF-8
4. Preflight
python --version
robot --version
robot --dryrun --outputdir evidence/dryrun suites/checkpoint.robot
Dry run should resolve all lifecycle keywords. It does not demonstrate actual teardown or timeout behavior.
5. Execute each matrix row into separate evidence
robot --include case-pass --variable RUN_ID:pass-001 --outputdir evidence/pass suites/checkpoint.robot
robot --include case-body-fail --variable RUN_ID:body-001 --outputdir evidence/body suites/checkpoint.robot
robot --include case-setup-fail --variable RUN_ID:setup-001 --outputdir evidence/setup suites/checkpoint.robot
robot --include case-timeout --variable RUN_ID:timeout-001 --outputdir evidence/timeout suites/checkpoint.robot
Only the first command should exit successfully. Preserve the other three output directories; their non-zero status is part of the checkpoint.
6. Verify predictions from trace and result hierarchy
For each run, inspect trace.txt, log.html,
and output.xml. Confirm:
- the setup-failed case has no body marker but does have teardown markers;
- the timeout case has no body-end marker but does have teardown markers;
-
the body-failed case preserves
checkpoint-primary-failure; - every run ends with suite teardown markers;
- the guarded scratch root is absent after execution.
9. Refactor shared state into deterministic isolation
Move file creation into Test Setup and deletion into
Test Teardown, with a unique per-test filename. The
suite setup may still create the guarded parent directory if that
parent itself is immutable shared infrastructure. Re-run the tests
together, individually, and in reversed source order. All should
have the same outcome.
10. Produce a lifecycle convention for the project
| Concern | Convention |
|---|---|
| Mutable state | Owned by the narrowest test/task/keyword scope; unique IDs for future parallelism |
| Suite setup | Only genuinely shared/immutable prerequisite; failure intentionally blocks suite |
| Teardown | Preserve first-failure evidence; clean exact owned resources; verify key postcondition |
| Timeout | Domain/library timeout first; Robot timeout is outer safety fuse, never a wait strategy |
| Tags | Stable classification/selection only; Test Tags as modern suite default |
| Reserved robot:* tags | Use only for documented execution semantics; never invent custom robot:* metadata |
| Evidence | Separate output directories for clean/failure experiments; never overwrite first failure before diagnosis |
11. Required evidence packet
- Robot and Python versions.
- Exact commands for PASS, body FAIL, setup FAIL, timeout, skip, and exclude runs.
trace.txtfrom each lifecycle case.-
output.xml,log.html, andreport.htmlfrom each run. - Proof that each guarded scratch root is absent after execution.
- Before/after source for the shared-state refactor.
- A one-page lifecycle convention using the table above.
12. Production operating model added by Chapter 09
Chapter 09 adds deterministic lifecycle ownership to the course’s operating model. A production Robot suite should make resource allocation, test isolation, cleanup, tag semantics, timeout budgets, and final failure evidence explicit. That discipline makes reruns meaningful and prepares the suite for future parallel execution rather than relying on source order or a clean developer machine.
13. Knowledge check
Why must setup-failure and timeout runs be executed separately during the checkpoint?
So each first-failure artifact is attributable and is not overwritten or mixed with unrelated failures.
What observation proves test teardown runs after setup failure?
The trace shows setup failure before any body marker, followed by test teardown markers and cleanup evidence.
What is the real defect if B passes alone but fails after A?
Order-dependent shared mutable state, not a reason to retry or force ordering.
Why is --skip preferable to --exclude when you need evidence that a known test was intentionally not run?
Skip keeps the test visible in logs/reports with SKIP status; exclude removes it from the execution result.
What Chapter 10 capability follows naturally from this lifecycle work?
Native IF/ELSE, loops, TRY/EXCEPT, BREAK/CONTINUE and structured control flow for expressing conditional lifecycle and recovery logic transparently.
14. Checkpoint complete
You can now reason about Robot Framework lifecycle from first principle: preparation has an owner, failures change control flow, teardowns still run, tags classify/select, timeouts bound but do not synchronize, and results represent the entire lifecycle. The next chapter builds native control-flow structures on top of this deterministic execution model.
Further reading
- Robot Framework 7.4.2 User Guide — test setup and teardown — defaults, overrides, teardown guarantees, and task aliases.
- Robot Framework 7.4.2 User Guide — execution flow — suite/test/keyword setup and teardown ordering and failure semantics.
- Robot Framework 7.4.2 User Guide — timeouts — test versus user-keyword timeout behavior and safety cautions.
- Robot Framework 7.4.2 User Guide — tags — Test Tags, reserved tags, include/exclude/skip semantics, and deprecations.
- Robot Framework 7.4.2 BuiltIn — Set Tags, Remove Tags, Skip/Skip If, and status/control helpers.
- Robot Framework on PyPI — current stable/pre-release stream and Python requirement.
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.