Chapter 15Lesson 02210–270 min

Command-Line Selection, Tag Expressions, Reruns, and Execution Profiles: Guided Hands-On Workflow

Build a disposable local selection lab, prove smoke/regression/environment slices, capture exact selection evidence, rerun only a controlled failed test, and merge without destroying the original failure.

Smoke sliceRegression slice--skip--rerunfailedRebot merge

Learning objectives

  • Create a five-test local suite whose selection counts are known before execution.
  • Run by test, suite, include/exclude, skip, and argument-file contracts.
  • Use a fake environment variable input without confusing it with a tag.
  • Create an intentional first failure, rerun only that test, and merge without overwriting original evidence.
  • Explain each filesystem/result mutation and its owner.

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. Core examples use python -m robot and python -m robot.rebot so the interpreter is explicit. RobotCode is not Robot Framework core; where shown as an optional profile layer, the pinned example is RobotCode 2.7.0, which requires Python 3.10+ and Robot Framework 5.0+. Mandatory labs do not require RobotCode, Pabot, browsers, containers, CI accounts, or paid services.

1. Scenario and safety boundary

The lab is deliberately local: five synthetic tests, no network, no subprocess, no real credentials, and all outputs under a dedicated results/ directory. The only state changes are Robot result artifacts. This keeps the lesson focused on selection and rerun semantics.

Safety rule: never reuse these commands against production targets merely by changing a variable. This suite contains no external integration by design. Chapter 16 introduces browser state explicitly.

2. Preflight and project tree

python --version
python -m robot --version
# Expect Robot Framework 7.4.2 for the pinned walkthrough.

mkdir rf-cli-lab
cd rf-cli-lab
# Create these paths manually or with your editor:
# tests/service.robot
# tests/environment.robot
# config/smoke.args
# results/   (created by Robot)
rf-cli-lab/
├── config/
│   └── smoke.args
├── tests/
│   ├── service.robot
│   └── environment.robot
└── results/             # generated evidence only

3. Create deterministic source with known tag membership

*** Settings ***
Documentation    Synthetic service checks for CLI selection.

*** Variables ***
${TARGET_ENV}       local
${FORCE_FAILURE}    no

*** Test Cases ***
Health Is Smoke
    [Tags]    smoke    regression
    Should Be Equal    ${TARGET_ENV}    local

Invoice Is Regression
    [Tags]    regression
    Should Be Equal    ${TARGET_ENV}    local

Archive Is Slow Regression
    [Tags]    regression    slow
    Should Be Equal    ${TARGET_ENV}    local

Controlled Failure
    [Tags]    regression    rerun-demo
    IF    $FORCE_FAILURE == "yes"
        Fail    Synthetic rerun contract failure
    END
    Should Be Equal    ${FORCE_FAILURE}    no

$FORCE_FAILURE is used as an expression variable so the string value is compared as a Python value rather than inserted into expression text. No external state changes: only Robot status/result state changes when the synthetic failure is enabled.

*** Settings ***
Documentation    Environment variant with explicit configuration.

*** Variables ***
${TARGET_ENV}      local
${EXPECTED_ENV}    local

*** Test Cases ***
Environment Contract
    [Tags]    smoke    env
    Should Be Equal    ${TARGET_ENV}    ${EXPECTED_ENV}

4. Predict the selection matrix before running

Slice Selector Predicted tests Count
Smoke --include smoke Health Is Smoke; Environment Contract 2
Regression --include regression Health; Invoice; Archive; Controlled Failure 4
Regression, not slow --include regression --exclude slow Health; Invoice; Controlled Failure 3
Environment --include env Environment Contract 1
Service suite --suite Tests.Service Four tests from service.robot 4

This prediction is evidence in its own right. If the observed counts differ, investigate selection first instead of assuming the tests are wrong.

5. Baseline run and name selection

# From rf-cli-lab/ only.
python -m robot --outputdir results/all tests

# Smallest controlled slice by test name.
python -m robot --test "Health Is Smoke" --outputdir results/one tests

# Preserve the root suite while selecting its Service child.
python -m robot --suite "Tests.Service" --outputdir results/service tests

The first run should report five PASS tests. The test-only run should report one PASS. The suite run should report the four service tests. In each directory, inspect output.xml, log.html, and report.html. These files are newly created filesystem evidence; the source remains unchanged.

6. Run smoke/regression/skip slices and compare evidence

python -m robot --include smoke --outputdir results/smoke-manual tests
python -m robot --include regression --exclude slow --outputdir results/regression-fast tests
python -m robot --include regression --skip slow --outputdir results/regression-with-skip tests
Run Expected PASS Expected SKIP Expected omitted
smoke-manual 2 0 3 non-smoke tests
regression-fast 3 0 Archive Is Slow Regression
regression-with-skip 3 1 Environment Contract (not regression)

The third command proves the semantic difference: Archive Is Slow Regression is visible as SKIP. In the second it is excluded and does not represent a selected skipped test.

7. Turn the smoke contract into a core argument file

# config/smoke.args
--include smoke
--exclude slow
--variable TARGET_ENV:local
--variable EXPECTED_ENV:local
--outputdir results/smoke-args
tests
python -m robot --argumentfile config/smoke.args

Expected count: 2 PASS. The file is Robot Framework core configuration. It sets no secret and touches no external system. Keep the exact file in version control if it defines a team execution contract.

cwd experiment: from the parent directory, running python -m robot --argumentfile rf-cli-lab/config/smoke.args will not make the embedded tests data-source path relative to config/. The safest course contract is “change to the project root first,” or normalize absolute/project-root paths in a launcher. Do not repair this with random PYTHONPATH changes.

8. Environment variant: configuration is a variable, selection is a tag

python -m robot --include env \
  --variable TARGET_ENV:qa \
  --variable EXPECTED_ENV:qa \
  --outputdir results/env-qa tests

Exactly one test should run and pass. The env tag selects the test; TARGET_ENV and EXPECTED_ENV configure its synthetic value. This separation scales cleanly into CI because changing environment does not require changing test ownership tags.

9. Create and preserve an intentional first failure

python -m robot \
  --variable FORCE_FAILURE:yes \
  --outputdir results/initial \
  --output original.xml \
  tests

The process should return non-zero because Controlled Failure fails. This is expected for the lab. Do not append --nostatusrc, do not delete results/initial/original.xml, and do not put this command in an && chain that prevents you from inspecting evidence after the expected failure.

Evidence to record: five tests selected, one failure, the exact message Synthetic rerun contract failure, and the original output path.

10. Rerun only failed tests with changed synthetic input

python -m robot \
  --rerunfailed results/initial/original.xml \
  --variable FORCE_FAILURE:no \
  --outputdir results/rerun \
  --output rerun.xml \
  tests

Only Controlled Failure should run. It should pass. The rerun output is a new artifact; it does not mutate the original. If Robot says the prior output has no failed tests, stop and confirm you pointed at the expected original rather than using --runemptysuite to suppress the diagnostic.

11. Merge as a derived result, then verify provenance

python -m robot.rebot --merge \
  --outputdir results/final \
  --output merged.xml \
  --log merged-log.html \
  --report merged-report.html \
  results/initial/original.xml \
  results/rerun/rerun.xml

The merged result should show five tests and no final failures because the matching failed test was replaced by its rerun result. Your evidence packet must still contain both inputs. A release process may decide that “pass after rerun” needs separate approval; merging is a result operation, not a policy waiver.

12. Inspect output evidence without guessing

# Cross-platform Python inspection; read-only.
python - <<'PY'
from pathlib import Path
import xml.etree.ElementTree as ET
for p in [
    Path("results/initial/original.xml"),
    Path("results/rerun/rerun.xml"),
    Path("results/final/merged.xml"),
]:
    root = ET.parse(p).getroot()
    tests = root.findall(".//test")
    statuses = [t.find("status").get("status") for t in tests if t.find("status") is not None]
    print(p, len(tests), statuses)
PY

This parser reads files only. It does not prove every semantic detail of the Robot result model, but it independently checks counts/statuses and the fact that all three evidence files exist.

13. Challenge: choose the right layer

You need a pull-request lane that runs all smoke tests except slow ones against synthetic environment qa. Which information belongs in tags and which belongs in variables? Then decide whether a one-off local command or committed argument file is the better contract. Explain the decision before running anything.

Verification and cleanup

  • Baseline: 5 PASS.
  • Smoke: 2 PASS.
  • Regression excluding slow: 3 PASS.
  • Regression skipping slow: 3 PASS + 1 SKIP.
  • Environment slice: 1 PASS.
  • Initial controlled run: 4 PASS + 1 FAIL.
  • Rerun: only Controlled Failure, PASS.
  • Merged: 5 tests, final PASS, with original and rerun inputs retained.
# Cleanup only the disposable lab you created.
cd ..
# PowerShell: Remove-Item -Recurse -Force .\rf-cli-lab
# Bash:       rm -rf ./rf-cli-lab

Knowledge check

Why does --rerunfailed still need the current test source path?

The regression-with-skip run reports three PASS and one SKIP. Why is that not equivalent to excluding slow?

What is the first thing to inspect when smoke unexpectedly runs three tests instead of two?

Why is changing FORCE_FAILURE from yes to no acceptable here?

Summary and bridge

You now have a reproducible selection/rerun lab with measurable evidence. Lesson 3 generalizes it into design decisions and precedence rules so teams can choose the simplest configuration surface that stays diagnosable.

Next lesson

Command-Line Selection, Tag Expressions, Reruns, and Execution Profiles: Configuration, Design Patterns, and Trade-Offs

Continue with Command-Line Selection, Tag Expressions, Reruns, and Execution Profiles: Configuration, Design Patterns, and Trade-Offs. It builds directly on the state, evidence, and operating assumptions established here, so carry those constraints forward rather than treating the next page as an isolated topic.

References and version anchors

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.