Skip to content

A class-based library with state

Chapter lab: Custom librariesch18-custom-libraries.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 ch18-custom-libraries.zip

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

Terminal window
curl -fsSLO https://manykarim.github.io/robotframework-essentials-web/labs/ch18-custom-libraries.zip && unzip -q ch18-custom-libraries.zip && rm ch18-custom-libraries.zip

Open the folder in VS Code with code rfe-ch18-custom-libraries (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-ch18-custom-libraries/
    • Directory.vscode/
      • extensions.json
    • Directorychecks/
      • smoke.robot
    • Directorylibraries/
      • README.md
    • Directoryvariables/
      • README.md
    • .gitignore
    • .python-version
    • LAB.md
    • pyproject.toml
    • README.md
    • requirements.txt
    • uv.lock

Module functions are perfect when each keyword stands alone. But some keywords need to remember things between calls — a cart that accumulates items, a client that stays logged in. For that you write a class.

Robot Framework imports the class and calls its @keyword-decorated methods. The @library(scope=...) decorator controls how long one instance lives: scope="TEST" gives every test a fresh instance, so state never leaks between tests. Reach for state only when keywords genuinely share it — a stateless module library is simpler when it fits.

@library(scope=...) instance lifetimestack diagram. scope=TEST keeps state from leaking between testsGLOBALone instance for the whole runSUITEa fresh instance per suiteTESTa fresh instance per testscope=TEST keeps state from leaking between tests
Edit

Goal: create libraries/CartMath.py — a TEST-scoped class CartMath with add_item_price(price) that stores a price and cart_total_should_be(expected) that checks the running total. (The file name matches the class name — that is how Robot Framework finds it.)

Here is the same shape over different data — a scoreboard. Adapt it to a cart of prices.

Worked example — adapt it, don’t copy it

from robot.api.deco import keyword, library
@library(scope="TEST")
class ScoreBoard:
def __init__(self):
self.points = []
@keyword
def add_points(self, points: int):
self.points.append(points)
@keyword
def score_should_be(self, expected: int):
actual = sum(self.points)
if actual != expected:
raise AssertionError(f"Score {actual}, expected {expected}")

Done when

libraries/CartMath.py defines a CartMath class whose methods are Robot keywords.

Hint 1

Decorate the class with @library(scope="TEST") and give it def __init__(self): self.prices = [].

Hint 2

Decorate each method with @keyword. add_item_price appends to self.prices; cart_total_should_be compares sum(self.prices) to expected and raises on a mismatch.

Solution
from robot.api.deco import keyword, library
@library(scope="TEST")
class CartMath:
def __init__(self):
self.prices = []
@keyword
def add_item_price(self, price: float):
self.prices.append(price)
@keyword
def cart_total_should_be(self, expected: float):
actual = sum(self.prices)
if actual != expected:
raise AssertionError(f"Cart total {actual}, expected {expected}")
Run

Create checks/cart.robot:

*** Settings ***
Library ../libraries/CartMath.py
*** Test Cases ***
Cart Adds Up
Add Item Price 19.90
Add Item Price 12.00
Cart Total Should Be 31.90

Run it:

Terminal window
uv run robot checks/cart.robot
Terminal window
robot checks/cart.robot
Terminal window
poetry run robot checks/cart.robot

Done when

the test Cart Adds Up passes.

Check your understanding

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

  1. @library(scope="TEST") means each test gets…

    Show the answer

    Answer: a fresh library instance — TEST scope constructs a new instance per test, so state never leaks between tests.

  2. How does Robot Framework find the class in a class library file?

    Show the answer

    Answer: a class whose name matches the file name — CartMath.py must contain a class CartMath; the file name matches the class.

Key terms

@library(scope=...)concept
Control instance lifetime: TEST, SUITE, or GLOBAL.
@keywordconcept
Mark a method as a Robot Framework keyword.

All terms in the glossary →