Skip to content

A result visitor

Chapter lab: Shaping data and resultsch21-shaping-data-and-results.zip · 4 KB

This lesson continues in the same lab as the lesson before it. If you don’t have it yet, download it here.

Download ch21-shaping-data-and-results.zip

Or fetch and unpack it from a terminal in VS Code:

Terminal window
curl -fsSLO https://manykarim.github.io/robotframework-essentials-web/labs/ch21-shaping-data-and-results.zip && unzip -q ch21-shaping-data-and-results.zip && rm ch21-shaping-data-and-results.zip

Open the folder in VS Code with code rfe-ch21-shaping-data-and-results (or File → Open Folder…) and accept the recommended RobotCode and Python extensions. Then set it up:

Terminal window
uv sync
Terminal window
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Keep the environment active in every terminal where you run lesson commands.

Terminal window
poetry install --no-root

Python 3.13 or newer is required; uv installs it when it is missing.

Open in browserNo setup? Try the lab right here: its files, an editor and a terminal, running in your browser.

What's inside
  • Directoryrfe-ch21-shaping-data-and-results/
    • Directory.vscode/
      • extensions.json
    • Directorychecks/
      • orders.robot
    • Directorydata/
      • orders.csv
    • Directoryext/
      • README.md
    • .gitignore
    • .python-version
    • LAB.md
    • pyproject.toml
    • README.md
    • requirements.txt
    • uv.lock

A pre-run modifier shapes what runs. A result visitor shapes what you do with the results — the output.xml a run produces. It is a ResultVisitor: Robot Framework walks the finished suites and tests and calls your methods, so you can build a custom report, compute metrics, or export data.

Because results live in output.xml, you can process them after the run, with rebot, without re-running anything — reporting is decoupled from execution.

A result visitor walks the resultstree diagram. Processed after the run with rebot, decoupled from executionoutput.xmlsaved after the runSuiteend_suite fires per suiteTestvisit_test fires per finished testProcessed after the run with rebot, decoupled from execution

Task 1 — Turn results into a markdown report

Section titled “Task 1 — Turn results into a markdown report”
Edit

Goal: create ext/ResultReport.py — a ResultVisitor that collects each finished test and, at the end of the top suite, writes results/rebot_report.md as a markdown table.

Here is the same base class with a different job — recording only the failures. Adapt it to collect every test into a table.

Worked example — adapt it, don’t copy it

import pathlib
from robot.api import ResultVisitor
class FailReport(ResultVisitor):
def __init__(self):
self.failed = []
def visit_test(self, test):
if test.status == "FAIL":
self.failed.append(test.name)
def end_suite(self, suite):
if suite.parent is not None:
return
pathlib.Path("results").mkdir(exist_ok=True)
pathlib.Path("results/failures.txt").write_text("\n".join(self.failed) + "\n", encoding="utf-8")

Done when

ext/ResultReport.py defines a ResultVisitor.

Hint 1

Collect rows as you visit: def visit_test(self, test): appends (test.name, test.status) to self.rows.

Hint 2

Write once, at the top suite. end_suite fires for every suite, so guard on the root: if suite.parent is not None: return, then build the table and write_text it to results/rebot_report.md.

Solution
import pathlib
from robot.api import ResultVisitor
class ResultReport(ResultVisitor):
def __init__(self):
self.rows = []
def visit_test(self, test):
self.rows.append((test.name, test.status))
def end_suite(self, suite):
if suite.parent is not None:
return
lines = ["| Test | Status |", "| --- | --- |"]
lines += [f"| {name} | {status} |" for name, status in self.rows]
pathlib.Path("results").mkdir(exist_ok=True)
pathlib.Path("results/rebot_report.md").write_text("\n".join(lines) + "\n", encoding="utf-8")
Run

Run the suite once to produce output.xml, then build your report from it with rebot — no tests re-run:

Terminal window
uv run robot --outputdir results checks/orders.robot
uv run rebot --prerebotmodifier ext/ResultReport.py results/output.xml
Terminal window
robot --outputdir results checks/orders.robot
rebot --prerebotmodifier ext/ResultReport.py results/output.xml
Terminal window
poetry run robot --outputdir results checks/orders.robot
poetry run rebot --prerebotmodifier ext/ResultReport.py results/output.xml

Done when

results/rebot_report.md is a table built from the saved results.

Check your understanding

Quick recall. Your first answer stays in this browser; the quiz never blocks your progress.

  1. A result visitor works on…

    Show the answer

    Answer: the results in output.xml after a run — A ResultVisitor walks the finished results, so reporting is decoupled from execution.

  2. How do you reprocess a saved run without re-running tests?

    Show the answer

    Answer: rebot --prerebotmodifier Visitor.py output.xml — rebot reads output.xml and applies your visitor — no tests execute.

Key terms

ResultVisitorconcept
Walk finished results; build reports or metrics from output.xml.
rebotcommand
Reprocess a saved output.xml into new reports.

All terms in the glossary →