Robot Framework vs pytest: When to Use Each
Robot Framework and pytest both run Python under the hood, both have extensive library ecosystems, and both can test web apps, APIs, and more. Yet they make opposite tradeoffs, attract different users, and serve different needs. Picking the wrong one costs months of accumulated friction.
This is a direct comparison — no hype, no marketing framing.
Syntax Side by Side
The most obvious difference is how tests look.
pytest:
# tests/test_login.py
import pytest
from playwright.sync_api import Page
def test_valid_login_redirects_to_dashboard(page: Page, base_url: str):
page.goto(f"{base_url}/login")
page.fill("#username", "admin")
page.fill("#password", "secret123")
page.click("button[type='submit']")
page.wait_for_url("**/dashboard")
assert page.title() == "Dashboard"
def test_invalid_password_shows_error(page: Page, base_url: str):
page.goto(f"{base_url}/login")
page.fill("#username", "admin")
page.fill("#password", "wrong")
page.click("button[type='submit']")
error = page.locator(".error-message")
assert error.is_visible()
assert error.text_content() == "Invalid credentials"Robot Framework:
# tests/login_tests.robot
*** Settings ***
Library SeleniumLibrary
Resource ../resources/login_page.resource
*** Test Cases ***
Valid Login Redirects To Dashboard
Navigate To Login Page
Enter Credentials admin secret123
Submit Login Form
Current URL Should Contain /dashboard
Page Title Should Be Dashboard
Invalid Password Shows Error Message
Navigate To Login Page
Enter Credentials admin wrong
Submit Login Form
Element Should Be Visible css=.error-message
Element Text Should Be css=.error-message Invalid credentialsThe RF version reads more like English. The pytest version reads more like code. This isn't a trivial difference — it determines who can maintain your tests.
Keyword-Driven vs Code-Driven
This is the fundamental model difference, not just a syntax preference.
Robot Framework's keyword model:
- Tests are composed of keywords
- Keywords abstract implementation details
- Tests can be written/read by non-developers
- Logic lives in keyword implementations (Python or RF keywords)
- Tests describe what happens, not how
pytest's code-driven model:
- Tests are Python functions
- Implementation is directly in the test or in helper functions/fixtures
- Full Python expressiveness always available
- Tests describe what happens using Python idioms
- Developers are first-class citizens
The RF model enforces a separation between "what to test" and "how to test it." That's valuable when the people writing tests aren't the same people implementing them. It's overhead when everyone is a developer.
Where the keyword model breaks down:
Complex conditional logic in RF is painful:
# RF — verbose and hard to follow
*** Keywords ***
Process User Based On Role
[Arguments] ${user}
${is_admin}= Evaluate '${user}[role]' == 'admin'
Run Keyword If ${is_admin} Verify Admin Dashboard Features
... ELSE Verify Viewer Dashboard Features
${has_billing}= Evaluate '${user}[plan]' == 'pro'
Run Keyword If ${has_billing} Verify Billing Tab Is Visible
... ELSE Verify Billing Tab Is Hidden# pytest — straightforward
def test_dashboard_based_on_role(page, user):
if user['role'] == 'admin':
verify_admin_dashboard_features(page)
else:
verify_viewer_dashboard_features(page)
if user['plan'] == 'pro':
assert page.locator('.billing-tab').is_visible()
else:
assert not page.locator('.billing-tab').is_visible()Team Skill Requirements
This is often the deciding factor.
For Robot Framework, you need:
- Someone who understands the keyword model and can architect resource files
- Python skills for custom library keywords
- RF-specific knowledge (variable scoping, execution model, settings sections)
- Discipline to maintain keyword abstractions as the app evolves
For pytest, you need:
- Python proficiency (at minimum intermediate level)
- Understanding of pytest fixtures and conftest.py patterns
- Knowledge of the chosen testing library (Playwright, Selenium, etc.)
If your QA team includes people who don't code, RF gives them a path to writing tests. If everyone is a developer, pytest keeps things in familiar territory with better tooling support (IDE autocomplete, type checking, debuggers).
The hybrid trap: Teams often think "we'll use RF so non-developers can write tests, and developers will implement the keywords." In practice, the non-developers still need significant training to write maintainable RF tests, and the developers end up writing most tests anyway. Be honest about your team composition before committing to RF for this reason.
Ecosystem and Libraries
pytest ecosystem:
pytest-playwright— Playwright integration (better browser automation than Selenium)pytest-asyncio— async test supportpytest-xdist— parallel executionpytest-cov— coverage reportingresponses,httpretty— HTTP mockingfactory_boy,faker— test data generationpytest-benchmark— performance testing- Hundreds more on PyPI
Robot Framework ecosystem:
SeleniumLibrary— Selenium WebDriverrobotframework-browser— Playwright-based (newer, better)RequestsLibrary— HTTP/API testingDatabaseLibrary— direct DB accessSSHLibrary— SSH automationAppiumLibrary— mobile testingrobotframework-pabot— parallel execution
Both ecosystems are mature. pytest's ecosystem is larger and more actively developed — it benefits from the broader Python testing community. RF's ecosystem is more specialized toward acceptance testing use cases.
Library quality: Third-party RF libraries vary significantly in quality and maintenance status. Before adopting a library, check when it was last updated and how many open issues it has. Some popular libraries have gone unmaintained.
Performance
Raw execution speed is comparable — both run Python ultimately. The overhead differences are:
RF overhead per test:
- Keyword dispatch machinery (~negligible)
- Logging infrastructure (RF logs everything by default, including keyword arguments)
- Report generation at the end of execution
pytest overhead per test:
- Fixture setup/teardown
- Plugin hooks
In practice, the bottleneck is always your test actions (browser operations, API calls, database queries), not the framework. The framework overhead is noise.
Parallel execution: pytest-xdist vs pabot. Both work. pytest-xdist is simpler to configure for pure Python tests. pabot handles RF-specific concerns (shared test data, resource locks) better.
Reporting
RF reporting — built-in, excellent:
log.html: keyword-level trace with timestamps, always generatedreport.html: high-level summary with tag breakdowns- No configuration needed
- Integrates with Allure for richer reports
pytest reporting — requires plugins:
- Default output: terminal only
pytest-htmlfor HTML reports- Allure integration via
allure-pytest - JUnit XML via
--junitxml - More flexible but requires setup
If you need rich reports that non-developers can interpret, RF's built-in reports have an edge. If you control the CI environment and are comfortable with plugins, pytest's ecosystem covers everything.
Maintenance Burden
This is where many teams underestimate RF.
RF maintenance costs:
- Keyword refactoring requires updating all callers (no IDE rename support across .robot files)
- Locator changes in page resources must be found/replaced across files
- RF syntax errors appear at runtime, not during editing
- Limited IDE support (VS Code extension exists but is less capable than Python tooling)
- Debugging requires reading RF-format tracebacks
pytest maintenance costs:
- Python refactoring tools work fully (PyCharm, VS Code)
- Type hints + mypy catch errors before runtime
- Standard Python debugging (pdb, IDE debugger) works
- Test isolation via fixtures is explicit and powerful
Over time, pytest projects benefit from Python's mature tooling. RF projects accumulate friction as the codebase grows, especially around finding and updating locators and keywords.
Hybrid Approaches
You don't have to choose one exclusively.
RF for acceptance tests, pytest for unit/integration tests: Common in enterprises. RF handles the high-level acceptance test suite (run by QA), pytest handles unit and integration tests (run by developers). Different audiences, different tools.
tests/
acceptance/ # Robot Framework
login.robot
checkout.robot
unit/ # pytest
test_pricing.py
test_auth.py
integration/ # pytest
test_api.pypytest calling RF tests: You can invoke Robot Framework from pytest using subprocess for mixed reporting:
# tests/test_rf_suite.py
import subprocess
import pytest
def test_robot_acceptance_suite():
result = subprocess.run(
['robot', '--outputdir', '/tmp/rf-results/', 'tests/acceptance/'],
capture_output=True
)
assert result.returncode == 0, f"RF tests failed:\n{result.stdout.decode()}"RF with Python libraries for complex logic: Write the complex logic in Python library keywords, keep the test DSL in RF:
# libraries/DataValidator.py
from robot.api.deco import keyword
class DataValidator:
@keyword('JSON Response Should Match Schema')
def json_should_match_schema(self, response_json, schema_file):
import jsonschema, json
with open(schema_file) as f:
schema = json.load(f)
jsonschema.validate(response_json, schema) # Raises on validation failure*** Test Cases ***
API Response Matches Schema
${response}= GET On Session api /users
JSON Response Should Match Schema ${response.json()} schemas/users-list.jsonDecision Framework
Answer these questions in order:
1. Who writes and maintains the tests?
- Mixed team (developers + QA + business analysts): RF is worth considering
- All developers: pytest
- Mostly developers with occasional non-developer input: pytest with good helper abstractions
2. What are you testing?
- Pure unit tests: pytest (RF is wrong for this)
- Pure API tests: either works, pytest is simpler
- Web UI acceptance tests: both work, RF has readability advantage
- Mixed (API + UI + DB): both work, RF's unified report is valuable
3. Do you need rich reports without configuration?
- Yes, for stakeholders who need to interpret results: RF's built-in reports help
- No, team-only consumption and you control CI: pytest + plugins is fine
4. What's your existing codebase?
- Python project with existing pytest: add to pytest, don't add RF
- Non-Python project (Java, .NET, etc.): RF is language-agnostic, fits better
- Greenfield: both are options, default to pytest unless criteria above point to RF
5. Long-term maintenance priority?
- Refactoring and evolving tests aggressively: pytest (better tooling)
- Stable test suite with infrequent changes: RF's overhead is manageable
The honest default: If you're a developer or developer-led team, default to pytest. It gives you Python's full power, better tooling, and less framework-specific knowledge to maintain. Reach for Robot Framework when you have a genuine need for keyword-driven readability — typically because non-developers are writing or reviewing tests, or because you need RF's specific libraries (SSHLibrary, AppiumLibrary in RF style) or its unified reporting across diverse test types.
RF isn't better or worse than pytest — it's optimized for different constraints. Teams that struggle with RF usually picked it for the wrong reasons. Teams that thrive with it usually have the specific team composition and reporting needs that RF's model addresses.