Modular Python packages for maintainable, BDD-style automated tests with pytest
, Hamcrest
, Allure
reporting, and configurable logging.
Technology-agnostic; example REST and Selenium implementations included.
qa-automation-python/
βββ qa-testing-utils/ # Shared low-level utility functions
βββ qa-pytest-commons/ # Technology-agnostic test infrastructure
βββ qa-pytest-rest/ # REST-specific steps and config
βββ qa-pytest-webdriver/ # Selenium-specific implementation
βββ qa-pytest-template/ # Cookiecutter project template
βββ qa-pytest-examples/ # Usage examples for application test projects
βββ pyproject.toml # Root environment definition for PDM
βββ .vscode/ # Recommended settings for VSCode integration
Support for additional technologies, e.g. RabbitMQ, can be added by sub-classing these classes and adding specific steps, setup/teardown, and configuration. This allows reusing the basic configuration, reporting, logging, and retrying mechanisms. Further, application tests, steps, and configurations reuse by subclassing from technologies.
flowchart TD
A[Tests: Define BDD scenarios as series of steps, also define specific setup and teardown] --> |contains| B[Steps: encapsulate UI or API operations and verifications, and may be composed of other steps]
B --> |contains| C[Configurations: can be per environment, such as dev, qa, staging, and contain URLs, users, authentication schemes, encryption, etc.]
B --> |uses| D[Matchers: Hamcrest matchers for single objects or for iterables]
A --> |contains| C
B --> |uses| E[Models: domain objects]
subgraph Inheritance
A1[GenericTests] -.-> |inherits| A2[Tests]
B1[GenericSteps] -.-> |inherits| B2[Steps]
C1[AbstractConfiguration] -.-> |inherits| C2[Configuration]
end
To add support for a new technology (e.g., messaging, database), create:
MyTechConfiguration(BaseConfiguration)
MyTechSteps(GenericSteps[MyTechConfiguration])
MyTechTests(AbstractTestsBase[MyTechSteps, MyTechConfiguration])
This pattern ensures you reuse the core BDD, configuration, and reporting mechanisms.
classDiagram
%% Core Abstractions
class AbstractTestsBase {
<<abstract>>
+steps
+_configuration
+setup_method()
+teardown_method()
}
class GenericSteps {
<<abstract>>
+given
+when
+then
+and_
+with_
+retrying()
+eventually_assert_that()
}
class BaseConfiguration {
<<abstract>>
+parser
}
%% Technology-Specific Extensions
class RestTests
class RestSteps
class RestConfiguration
class SeleniumTests
class SeleniumSteps
class SeleniumConfiguration
%% Example: Custom Extension
class TerminalXTests
class TerminalXSteps
class TerminalXConfiguration
%% Relationships
AbstractTestsBase <|-- RestTests
AbstractTestsBase <|-- SeleniumTests
SeleniumTests <|-- TerminalXTests
GenericSteps <|-- RestSteps
GenericSteps <|-- SeleniumSteps
SeleniumSteps <|-- TerminalXSteps
BaseConfiguration <|-- RestConfiguration
BaseConfiguration <|-- SeleniumConfiguration
SeleniumConfiguration <|-- TerminalXConfiguration
RestTests o-- RestSteps : uses
RestTests o-- RestConfiguration : configures
SeleniumTests o-- SeleniumSteps : uses
SeleniumTests o-- SeleniumConfiguration : configures
TerminalXTests o-- TerminalXSteps : uses
TerminalXTests o-- TerminalXConfiguration : configures
%% Example extension note
%% You can add new technologies by subclassing the three core abstractions:
%% AbstractTestsBase, GenericSteps, and BaseConfiguration.
Key Classes (with links to source code):
Class | Description | Source |
---|---|---|
AbstractTestsBase |
Base for all test scenarios; holds steps and config | abstract_tests_base.py |
GenericSteps |
Base for all step implementations; provides BDD keywords | generic_steps.py |
BaseConfiguration |
Base for all configuration objects | base_configuration.py |
RestTests |
REST-specific test base | rest_tests.py |
RestSteps |
REST-specific steps | rest_steps.py |
RestConfiguration |
REST-specific configuration | rest_configuration.py |
SeleniumTests |
Selenium-specific test base | selenium_tests.py |
SeleniumSteps |
Selenium-specific steps | selenium_steps.py |
SeleniumConfiguration |
Selenium-specific configuration | selenium_configuration.py |
TerminalXTests |
Example: custom UI test base | terminalx_tests.py |
TerminalXSteps |
Example: custom UI steps | terminalx_steps.py |
TerminalXConfiguration |
Example: custom UI configuration | terminalx_configuration.py |
π Quick Start (Locally with PDM)
Open in Codespace or Dev Container and everything will get installed and configured, otherwise:
-
Install Python 3.13 on your system
-
Install PDM:
pipx install pdm[all]
-
Install dependencies:
pdm install
-
Run all tests from the root:
pdm run pytest
- branch
- commit changes
- pull request -- will trigger a build
- build succeeds --> tag with vX.X.X, e.g. v1.2.3 -- will trigger a release
- verify new versions appeared on https://pypi.org/
cd qa-automation-python
pdm plugin add pdm-init # if not already available
pdm init # or copy an existing module like qa-testing-utils
Then edit pyproject.toml
accordingly.
report.html
is generated in the root folder; just open it in a browserallure-results/
is generated for Allure reporting (requires Allure server). To view Allure reports, install Allure and run:allure serve allure-results/
Below are example test cases demonstrating BDD-style usage with this framework:
# Example: UI search test
# (Assumes self.login_section and self._configuration.users are defined)
def should_find(self):
self.login_section(random.choice(self._configuration.users))
for word in ["hello", "kitty"]:
(self.steps
.when.searching_for(word)
.then.the_search_hints(
yields_item(contains_string_ignoring_case(word))))
# Example: API add test
def should_add(self):
random_pet = SwaggerPetstorePet.random()
(self.steps
.when.adding(random_pet)
.then.the_available_pets(yields_item(is_(random_pet))))
- Python 3.13
- Google Chrome for local Selenium testing
- PDM (Python package manager)
TODO
- Add browser matrix support (Firefox, Safari, Edge)
- Make the BDD intro words appear in Allure report
- Extend test examples (API + UI)
This project is licensed under the Apache 2.0 License.