budtestlibrary
Universal Python test automation framework for HIL, SIL, web, mobile, cloud, API, security, performance, and end-to-end testing.
It provides lifecycle management, rich assertions, structured results, logging,
firmware-flashing abstractions, and optional Bloom PLM integration through
BloomMetaData attached to test classes.
Creator: Amine El Omari
Requirements
- Python 3.9 or later
- No required runtime dependencies
Installation
python -m pip install budtestlibrary
Features
BudTestCaselifecycle withsetUpClass()andtearDownClass().- Automatic discovery of methods whose names start with
bud_. - Boolean, equality, membership, range, tolerance, and regex assertions.
- Structured assertion and test-method results.
- Configurable source-location, traceback, and value capture.
- Coloured console output and plain serialised result data.
- Firmware flashing through
FlashEvent,FlashSuccess, andFlashFailure. - Environment-variable and
app.propertiesconfiguration. - Bundled examples for HIL, SIL, API, UI, cloud/E2E, and flashing scenarios.
- Optional Bloom PLM traceability with
BloomMetaData.
Quick start
import logging
from budtestlibrary import BloomMetaData, BudTestCase
class MyTest(BudTestCase):
bloom_metadata = BloomMetaData("PRJ", "001") # Optional: attach Bloom traceability metadata
def setUpClass(self):
self.log_info("Setting up test")
def bud_check_response(self):
response = get_response()
self.assertTrue(response.ok, msg="Response is successful")
def bud_validate_output(self):
result = compute_result()
self.assertInTolerance(
result,
expected=42.0,
absolute_tolerance=0.5,
msg="Output is within tolerance",
)
def tearDownClass(self):
self.log_info("Tearing down test")
if __name__ == "__main__":
test = MyTest()
test.set_loglevel(logging.INFO)
test.run()
Optional Bloom Traceability
BloomMetaData optionally links a test class to a Bloom test case using the
{Project}-TC-{ID} convention:
from budtestlibrary import BloomMetaData, BudTestCase
class TraceableTest(BudTestCase):
bloom_metadata = BloomMetaData("PRJ", "001")
This integration is optional. Tests run normally without Bloom metadata or a
Bloom deployment. When results flow through bud_runner into Bud, Bud uses the
metadata when the corresponding Bud project is linked to Bloom.
Public API
| Export | Purpose |
|---|---|
BudTestCase |
Base class for lifecycle, assertions, logging, and results |
BloomMetaData |
Optional Bloom PLM test-case traceability metadata |
FlashEvent |
Abstract firmware-flashing operation |
FlashSuccess |
Successful flashing result |
FlashFailure |
Failed flashing result with error information |
BudConfig |
Configuration loaded from environment and properties |
get_default_config() |
Shared lazy-loaded configuration instance |
Test structure
BudTestCase.run() discovers methods prefixed with bud_ and executes them in
alphabetical order. Prefix methods numerically when explicit ordering matters:
class OrderedTest(BudTestCase):
def bud_01_connect(self):
...
def bud_02_measure(self):
...
After execution, call get_results():
test = MyTest()
test.run()
for method_result in test.get_results():
print(method_result.method_name, method_result.passed)
Assertions
Available helpers include:
assertTrue/assertFalseassertEqual/assertNotEqualassertGreater/assertLessassertIn/assertNotInassertRegexassertInToleranceassertInRangeskipAssert
Example:
self.assertInRange(
actual=temperature,
lower_bound=18.0,
upper_bound=26.0,
include_bounds=True,
msg="Temperature is inside the accepted range",
)
Result capture
Subclass attributes control serialised result size and detail:
| Attribute | Default | Purpose |
|---|---|---|
CAPTURE_SOURCE_PATH |
True |
Capture failure source file and line |
CAPTURE_TRACEBACK |
True |
Capture traceback text |
MAX_RESULT_VALUE_LENGTH |
5000 |
Truncate long expected/actual/result values |
class CompactResultsTest(BudTestCase):
CAPTURE_SOURCE_PATH = False
CAPTURE_TRACEBACK = False
MAX_RESULT_VALUE_LENGTH = 500
Firmware flashing
Implement FlashEvent for product-specific flashing:
from budtestlibrary import FlashEvent, FlashSuccess
class MyFlashEvent(FlashEvent):
DEFAULT_ADDR = 0x08000000
def flash(self, firmware_path, addr=None):
perform_flash(firmware_path, self.DEFAULT_ADDR if addr is None else addr)
return FlashSuccess(message="Flashed successfully")
def get_project_name(self):
return "SensorHub"
def get_firmware_version(self):
return "2.1.0"
def get_release(self):
return "production"
addr is the optional target memory address (for example 0x08000000 on
STM32, 0x10000 on ESP32). Pass it through execute() when a run needs a
specific address, and omit it to use the implementation's default:
event = MyFlashEvent()
event.execute("firmware.bin") # implementation default
event.execute("bootloader.bin", addr=0x08000000) # explicit address
Implementations that do not need an address may keep the single-argument
flash(self, firmware_path) signature — execute() detects this and calls
them unchanged. Passing an explicit addr to such an implementation returns a
FlashFailure explaining that addr=None must be added to its signature.
Configuration
export BUD_BACKEND_URL="https://<your-bud-instance-url>"
export BUD_TOKEN="<user-token>"
budBackend=https://<your-bud-instance-url>
budRunnerAccount=lab-station-01
Keep secrets outside repositories.
Bundled examples
Examples ship inside the wheel under budtestlibrary.examples.
python -c "import budtestlibrary.examples, pathlib; print(pathlib.Path(budtestlibrary.examples.__file__).parent)"
| Example | Scenario |
|---|---|
minimal_test.py |
Minimal test with core assertions |
bloom_metadata_test.py |
Optional Bloom traceability |
flash_event_example.py |
Firmware flashing |
hil_test.py |
Hardware-in-the-loop |
sil_test.py |
Software-in-the-loop |
api_testing_example.py |
API testing |
ui_testing_example.py |
UI testing |
cloud_e2e_example.py |
Cloud and E2E testing |
Compatibility
budtestlibrary |
Intended bud_runner pairing |
Notes |
|---|---|---|
1.0.3 |
1.0.3 |
Optional addr target address on FlashEvent.flash() and FlashEvent.execute() |
1.0.2 |
1.0.2 |
Permanent AGPL wording clarified; examples and README coverage expanded |
1.0.1 |
1.0.1 |
Examples bundled in the wheel |
1.0.0.post2 |
1.0.0.post2 |
Configurable capture, flashing abstractions, and separated test-software metadata |
Development
git clone https://github.com/MbedLabs/bud-test-library.git
cd bud-test-library
python -m pip install -e ".[dev]"
black --check budtestlibrary/ examples/
isort --profile black --check-only budtestlibrary/ examples/
ruff check budtestlibrary/ examples/
mypy budtestlibrary/
pytest tests/ -v
Related packages
- bud_runner: CLI tool for test execution and Bud integration.
- pybudgui: Python Qt desktop client for manual test execution, planned on the roadmap.
Licence
budtestlibrary is permanent free and open-source software licensed under the
GNU Affero General Public License v3.0 only (AGPL-3.0-only).
No paid EmbedLabs licence is required to use budtestlibrary, including for
commercial use, provided the AGPL terms are followed. Accepted community
contributions remain publicly available under AGPL-3.0-only and will not
become proprietary-only.
Bud and Bloom are separate source-available applications. Commercial licensing,
deployment, integration, and support offered through sales@embedlabs.de
applies to those applications and services—not to the budtestlibrary package
licence.
Technical, security, and contribution questions: dev@embedlabs.net.
Copyright (C) 2026 Mohamed Amine El Omari Alaoui, operating under the name EmbedLabs.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file budtestlibrary-1.0.3.tar.gz.
File metadata
- Download URL: budtestlibrary-1.0.3.tar.gz
- Upload date:
- Size: 45.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
436cd61bd87cf8f79e4c7336316f40a8e9ce974a8f3fe8ac46464c40191905d8
|
|
| MD5 |
7dc4fb7bc780afaf80222120c3065532
|
|
| BLAKE2b-256 |
7bcaf7e65d78b478f7eaab3b525e63d9fa7c8e76a719b7e9a9094c383e1cf895
|
Provenance
The following attestation bundles were made for budtestlibrary-1.0.3.tar.gz:
Publisher:
ci-cd.yml on MbedLabs/bud-test-library
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
budtestlibrary-1.0.3.tar.gz -
Subject digest:
436cd61bd87cf8f79e4c7336316f40a8e9ce974a8f3fe8ac46464c40191905d8 - Sigstore transparency entry: 2519548765
- Sigstore integration time:
-
Permalink:
MbedLabs/bud-test-library@6f7989cb29a172d9bb3f89fbdd3078fc081d351f -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/MbedLabs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci-cd.yml@6f7989cb29a172d9bb3f89fbdd3078fc081d351f -
Trigger Event:
push
-
Statement type:
File details
Details for the file budtestlibrary-1.0.3-py3-none-any.whl.
File metadata
- Download URL: budtestlibrary-1.0.3-py3-none-any.whl
- Upload date:
- Size: 35.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b8f02b5ee084b621789cdcfe7c91eacdc925b1201182a60e99163188f7b7464
|
|
| MD5 |
c2fc746748df5fa821dd58a32ae9f6a9
|
|
| BLAKE2b-256 |
b173494262583aa7beb253a9fafb2151db3a08dfb1d727e6493566f976fc1ebe
|
Provenance
The following attestation bundles were made for budtestlibrary-1.0.3-py3-none-any.whl:
Publisher:
ci-cd.yml on MbedLabs/bud-test-library
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
budtestlibrary-1.0.3-py3-none-any.whl -
Subject digest:
7b8f02b5ee084b621789cdcfe7c91eacdc925b1201182a60e99163188f7b7464 - Sigstore transparency entry: 2519549067
- Sigstore integration time:
-
Permalink:
MbedLabs/bud-test-library@6f7989cb29a172d9bb3f89fbdd3078fc081d351f -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/MbedLabs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci-cd.yml@6f7989cb29a172d9bb3f89fbdd3078fc081d351f -
Trigger Event:
push
-
Statement type: