A listener that stores results in SQLite
Chapter lab: Listening to execution
This lesson continues in the same lab as the lesson before it. If you don’t have it yet, download it here.
Download ch20-listening-to-execution.zip
Or fetch and unpack it from a terminal in VS Code:
curl -fsSLO https://manykarim.github.io/robotframework-essentials-web/labs/ch20-listening-to-execution.zip && unzip -q ch20-listening-to-execution.zip && rm ch20-listening-to-execution.zipInvoke-WebRequest https://manykarim.github.io/robotframework-essentials-web/labs/ch20-listening-to-execution.zip -OutFile ch20-listening-to-execution.zip; Expand-Archive ch20-listening-to-execution.zip -DestinationPath .; Remove-Item ch20-listening-to-execution.zipOpen the folder in VS Code with code rfe-ch20-listening-to-execution (or File → Open Folder…) and accept the recommended RobotCode and Python extensions. Then set it up:
uv syncpython3 -m venv .venvsource .venv/bin/activatepip install -r requirements.txtpython -m venv .venv.venv\Scripts\Activate.ps1pip install -r requirements.txtKeep the environment active in every terminal where you run lesson commands.
poetry install --no-rootPython 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-ch20-listening-to-execution/
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 markdown table is easy to read; a database is easy to query. Python’s
standard library includes sqlite3 — a whole SQL database in a single file, no
server — so a listener can record every run into a table you can later query for
trends, flaky tests, or slowest cases.
The pattern is the same v3 listener: open the database when the run starts, insert a row per test, and commit when the run closes.
Task 1 — Record each result into a table
Section titled “Task 1 — Record each result into a table”Goal: create ext/SqliteResults.py — a v3 listener that creates a results
table in results/results.db and inserts each test’s name and status.
Here is the same shape writing to a different table — one keyed by tag. Adapt it to store name and status.
Worked example — adapt it, don’t copy it
import sqlite3import pathlib
class TagResults: ROBOT_LISTENER_API_VERSION = 3
def __init__(self): pathlib.Path("results").mkdir(exist_ok=True) self.db = sqlite3.connect("results/tags.db") self.db.execute("CREATE TABLE IF NOT EXISTS tags (test TEXT, tag TEXT)")
def end_test(self, data, result): for tag in data.tags: self.db.execute("INSERT INTO tags VALUES (?, ?)", (data.name, tag))
def close(self): self.db.commit() self.db.close()Done when
ext/SqliteResults.py defines a listener that uses sqlite3.
Hint 1
Open the database in __init__ and create the table:
self.db = sqlite3.connect("results/results.db") then
CREATE TABLE IF NOT EXISTS results (name TEXT, status TEXT).
Hint 2
Insert in end_test — INSERT INTO results VALUES (?, ?), (data.name, result.status) —
and commit() then close() in close().
Solution
import sqlite3import pathlib
class SqliteResults: ROBOT_LISTENER_API_VERSION = 3
def __init__(self): pathlib.Path("results").mkdir(exist_ok=True) self.db = sqlite3.connect("results/results.db") self.db.execute("CREATE TABLE IF NOT EXISTS results (name TEXT, status TEXT)")
def end_test(self, data, result): self.db.execute("INSERT INTO results VALUES (?, ?)", (data.name, result.status))
def close(self): self.db.commit() self.db.close()Task 2 — Run the suite with your listener
Section titled “Task 2 — Run the suite with your listener”uv run robot --listener ext/SqliteResults.py checks/orders.robotrobot --listener ext/SqliteResults.py checks/orders.robotpoetry run robot --listener ext/SqliteResults.py checks/orders.robotresults/results.db now holds a row per test. You could open it with any SQLite
tool and run SELECT * FROM results;.
Done when
results/results.db was created and contains the run’s tests.
Check your understanding
Quick recall. Your first answer stays in this browser; the quiz never blocks your progress.
Why store results in SQLite instead of a text file?
A database is queryable with SQL;
sqlite3is in the standard library, one file, no server.Show the answer
Answer: you can query it (trends, flaky tests, slowest cases) — A database is queryable with SQL;
sqlite3is in the standard library, one file, no server.When should the listener commit and close the database?
Insert per test in
end_test;commit()andclose()once inclose().Show the answer
Answer: in
close()at the end of the run — Insert per test inend_test;commit()andclose()once inclose().
Key terms
- sqlite3concept
- Standard-library SQL database in a single file — no server.
- close()concept
- Listener hook that fires once at the end of the whole run.