Setups, Teardowns, Tags, Timeouts, and Suite Lifecycle: Guided Hands-On Workflow
Instrument a disposable local suite so lifecycle order, tag selection, failure propagation, timeout behavior, filesystem state, and teardown guarantees are observable rather than assumed.
Learning objectives
- Create a guarded suite workspace and per-test files with suite/test setup and teardown.
- Record lifecycle markers in Robot output evidence so cleanup does not erase the proof.
- Run separate PASS, FAIL, and TIMEOUT slices and predict exact lifecycle order before execution.
- Use static and runtime tags and compare include, skip, and exclude semantics.
- Verify that cleanup removes only test-owned state while output.xml/log/report remain available.
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. Scenario: an observable lifecycle laboratory
The lab uses only Robot Framework core, BuiltIn, and the standard
OperatingSystem library. Each test gets a unique file under a
guarded scratch directory. A lifecycle marker is written under
${OUTPUT DIR}, which survives scratch cleanup and
therefore becomes independent evidence.
Failure injection is deliberate. One test calls
Fail; another uses Sleep only to trigger
a deterministic timeout. This is not a synchronization pattern.
Run the failure slices into separate output directories and
preserve them before repairing anything.
2. Project layout
rf09-lifecycle-lab/
├── suites/
│ └── lifecycle.robot
└── evidence/
3. Complete instrumented suite
*** Settings ***
Library OperatingSystem
Suite Setup Begin Suite Lifecycle
Suite Teardown End Suite Lifecycle
Test Setup Begin Test Lifecycle
Test Teardown End Test Lifecycle
Test Tags rf09 lifecycle
*** Variables ***
${RUN_ID} manual-001
${SCRATCH} ${TEMPDIR}/rf09-lifecycle-${RUN_ID}
${MARKERS} ${OUTPUT DIR}/lifecycle-markers.txt
${SUITE_OWNS_ROOT} ${False}
*** Test Cases ***
Passing Path
[Tags] demo-pass
Append Marker ${TEST NAME}|body-start
File Should Exist ${TEST_FILE}
Set Tags runtime-observed
Append Marker ${TEST NAME}|body-end
Failing Path
[Tags] demo-fail
Append Marker ${TEST NAME}|body-start
File Should Exist ${TEST_FILE}
Fail intentional-body-failure
Append Marker ${TEST NAME}|unreachable
Timed Out Path
[Tags] demo-timeout
[Timeout] 300 milliseconds
Append Marker ${TEST NAME}|body-start
Sleep 2 seconds
Append Marker ${TEST NAME}|unreachable
*** Keywords ***
Begin Suite Lifecycle
Guard Scratch
Directory Should Not Exist ${SCRATCH}
Create Directory ${SCRATCH}
Set Suite Variable ${SUITE_OWNS_ROOT} ${True}
Create File ${MARKERS} suite-setup\n
Begin Test Lifecycle
${safe}= Evaluate re.sub(r'[^A-Za-z0-9_.-]+', '_', $TEST_NAME) modules=re
${test_file}= Join Path ${SCRATCH} ${safe}.txt
Set Test Variable ${TEST_FILE} ${test_file}
Create File ${TEST_FILE} owned-by=${TEST NAME}\n
Append Marker ${TEST NAME}|test-setup
End Test Lifecycle
Append Marker ${TEST NAME}|test-teardown-start
Run Keyword And Ignore Error Remove File ${TEST_FILE}
File Should Not Exist ${TEST_FILE}
Append Marker ${TEST NAME}|test-teardown-end
End Suite Lifecycle
Append Marker suite-teardown-start
IF ${SUITE_OWNS_ROOT}
Guard Scratch
Remove Directory ${SCRATCH} recursive=True
Directory Should Not Exist ${SCRATCH}
ELSE
Log Scratch root was not created by this suite; leaving it untouched.
END
Append Marker suite-teardown-end
Guard Scratch
${candidate}= Normalize Path ${SCRATCH} case_normalize=True
${temp}= Normalize Path ${TEMPDIR} case_normalize=True
Should Start With ${candidate} ${temp}${/}
Should Contain ${candidate} rf09-lifecycle-
Append Marker
[Arguments] ${text}
Append To File ${MARKERS} ${text}\n ... encoding=UTF-8
4. Why one ignored cleanup call is acceptable here—and what it does not mean
Run Keyword And Ignore Error Remove File is used only
for an idempotent cleanup attempt: the next line still asserts that
the file is absent, so a real cleanup failure remains visible. We
are not converting a business failure into green status. In
production, a dedicated cleanup keyword or
TRY/EXCEPT can express the same intent more clearly;
Chapter 10 develops native control flow in depth.
5. Preflight
python --version
robot --version
robot --dryrun --outputdir evidence/dryrun suites/lifecycle.robot
The dry run proves parsing, imports, keyword resolution, tags, and
timeout syntax. It does not create files, run Sleep, or
exercise teardown behavior.
6. Run the PASS slice first
robot --include demo-pass --variable RUN_ID:pass-001 --outputdir evidence/pass suites/lifecycle.robot
Expected status: PASS. Open
evidence/pass/lifecycle-markers.txt. The expected
sequence is suite-setup → test-setup → body-start → body-end →
test-teardown-start → test-teardown-end → suite-teardown-start →
suite-teardown-end. Confirm runtime-observed appears in
the test’s final tags in the report/log.
7. Run the intentional failure slice
robot --include demo-fail --variable RUN_ID:fail-001 --outputdir evidence/fail suites/lifecycle.robot
# Expected command exit status: non-zero because the test fails.
The unreachable marker must be absent, but both test
teardown markers and suite teardown markers must exist. The final
error should still contain intentional-body-failure.
Confirm the scratch directory is absent after execution.
8. Run the timeout slice
robot --include demo-timeout --variable RUN_ID:timeout-001 --outputdir evidence/timeout suites/lifecycle.robot
# Expected: FAIL due to the 300 ms test timeout.
The 2-second Sleep is deliberately longer than the 300
ms test timeout. Robot stops the current body keyword, marks the
test failed, then runs test teardown. The teardown is not cut short
by the test timeout. This demonstrates timeout semantics only; never
use Sleep as a real readiness strategy.
9. Compare include, skip, and exclude
# Include only tests with demo-pass.
robot --include demo-pass --outputdir evidence/include suites/lifecycle.robot
# Keep demo-timeout visible as SKIP instead of executing it.
robot --skip demo-timeout --outputdir evidence/skip suites/lifecycle.robot
# Omit demo-timeout from the execution tree entirely.
robot --exclude demo-timeout --outputdir evidence/exclude suites/lifecycle.robot
--skip and --exclude are observably
different. A skipped test appears in logs/reports with SKIP status;
an excluded test is not part of the execution result. Neither option
creates isolation—the per-test setup still owns that job for tests
that do execute.
10. Evidence checklist
| Evidence | PASS run | FAIL run | TIMEOUT run |
|---|---|---|---|
| Body end marker | Present | Absent after Fail | Absent after timeout |
| Test teardown markers | Present | Present | Present |
| Suite teardown markers | Present | Present | Present |
| Scratch directory after run | Absent | Absent | Absent |
| Final status | PASS | FAIL | FAIL |
| Primary message | No failure | intentional-body-failure | test timeout message |
11. Small challenge
Add a fourth test tagged override whose
[Setup] uses a different keyword and whose
[Teardown] is explicitly empty. Predict which default
lifecycle hooks disappear, then verify from the marker file.
Afterward restore the default teardown; disabling cleanup is a
teaching experiment, not a production recommendation.
12. Knowledge check
Why are lifecycle markers stored under ${OUTPUT DIR} instead of the scratch workspace?
The scratch workspace is deleted by teardown. Output evidence must survive cleanup so the lifecycle can be diagnosed after the run.
Why is Sleep acceptable in the timeout case here?
Only as deterministic failure injection to demonstrate timeout semantics. It is explicitly not used as application synchronization.
Why does the failing test still clean its file?
Test teardown executes regardless of test status, including when the body fails.
What is the observable difference between --skip and --exclude?
Skipped tests remain in the execution result with SKIP status; excluded tests are omitted entirely.
13. Summary and next step
You have observed lifecycle order instead of memorizing it. PASS, FAIL, and TIMEOUT runs prove that teardown ownership is independent from body success, while tag selection changes execution membership rather than state isolation. Lesson 3 turns these observations into design decisions for suite versus test fixtures, timeouts, dynamic tags, and failure-preserving cleanup.
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.