A comprehensive, modular Python test automation framework supporting API, UI (Playwright/Selenium), Database, and functional testing.
- Configuration-Driven: YAML-based configuration with environment variable override support
- Modular Architecture: Pluggable client system for different testing targets
- Multiple Testing Types:
- REST API testing with session management and retries
- UI testing with Playwright and Selenium support
- Database testing with SQLAlchemy and MongoDB
- Mobile testing with Appium (optional)
- Test Harness: Custom test lifecycle with setup/run/teardown hooks
- Rich Assertions: Readable assertion library with multiple operators
- Multi-Tenant Support: Built-in tenant filtering for enterprise applications
- Page Object Model: Base classes for UI test organization
- CLI Interface: Command-line tool for test execution
# Basic installation
pip install -e .
# With UI testing support
pip install -e ".[ui]"
# With database support
pip install -e ".[database]"
# Full installation
pip install -e ".[all]"
# Development installation
pip install -e ".[all,dev]"playwright installfrom test_framework.core import TestCase, TestSuite, teststep, RunLevel
from test_framework.clients.api import RestClient
class TestGetUsers(TestCase):
run_level = RunLevel.RUN
title = "Verify GET /users returns data"
def setup(self):
self.api = self.suite.api_client
def run(self):
response = self.api.get("/users")
teststep.must("Status is 200", response.status_code, '==', 200)
teststep.must("Response is list", isinstance(response.json(), list), '==', True)
class MyAPITestSuite(TestSuite):
name = "My API Tests"
testcases = [TestGetUsers]
def setup(self):
self.api_client = RestClient(base_url="https://api.example.com")
def teardown(self):
self.api_client.close()# config/my_config.yaml
environment:
name: MY_API_TESTS
testsuite: tests.my_tests.test_api
targets:
api:
url: https://api.example.com
timeout: 30# Using CLI
testcli run config/my_config.yaml
# Run specific tests
testcli run config/my_config.yaml --test-cases TestGetUsers
# With tags
testcli run config/my_config.yaml --tags smoketest-automation-framework/
├── src/test_framework/
│ ├── core/ # Test harness
│ │ ├── test_case.py # TestCase base class
│ │ ├── test_suite.py # TestSuite orchestrator
│ │ ├── test_step.py # Assertions
│ │ ├── test_loader.py # Module discovery
│ │ └── test_runner.py # Execution engine
│ ├── clients/ # Client implementations
│ │ ├── api/ # REST API client
│ │ ├── ui/ # Playwright/Selenium
│ │ └── database/ # SQLAlchemy/MongoDB
│ ├── models/ # Data models
│ ├── utils/ # Utilities
│ └── config.py # Configuration loader
├── tests/examples/ # Example tests
└── docs/ # Documentation
Configuration supports three override levels (highest to lowest priority):
-
Environment Variables: Prefix with
TESTFW_export TESTFW_targets_api_url=http://localhost:8080 -
Configuration File: YAML format
targets: api: url: https://api.example.com
-
Default Configuration: Built-in defaults
The teststep module provides readable assertions:
# Must pass (raises on failure)
teststep.must("Check status", response.status_code, '==', 200)
teststep.must("User in list", user, 'in', users)
teststep.must("Has items", len(items), '>', 0)
# Should pass (logs warning on failure, doesn't raise)
teststep.should("Optional check", value, '>=', 0)
# Available operators:
# ==, !=, >, <, >=, <=
# in, not in, contains, not contains
# is, is not, is None, is not None
# isinstance, startswith, endswith, matches
# is True, is False, is truthy, is falsyfrom test_framework.clients.ui.playwright_client import PlaywrightPage
class LoginPage(PlaywrightPage):
USERNAME = "#username"
PASSWORD = "#password"
SUBMIT = "button[type='submit']"
def login(self, user: str, password: str):
self.fill(self.USERNAME, user)
self.fill(self.PASSWORD, password)
self.click(self.SUBMIT)Filter tests by tenant:
class TestTenantSpecific(TestCase):
run_level = RunLevel.RUN
include_tenants = ["tenant_a", "tenant_b"] # Only run for these
exclude_tenants = ["tenant_c"] # Skip for thesefrom test_framework.clients.api import RestClient
client = RestClient(
base_url="https://api.example.com",
timeout=30,
headers={"Authorization": "Bearer token"},
retry_count=3
)
# HTTP methods
response = client.get("/users")
response = client.post("/users", json={"name": "John"})
response = client.put("/users/1", json={"name": "Jane"})
response = client.delete("/users/1")
# Authentication
client.set_auth_token("new_token")- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
pytest - Submit a pull request
MIT License - see LICENSE file for details.