Skip to main content

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

  • BudTestCase lifecycle with setUpClass() and tearDownClass().
  • 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, and FlashFailure.
  • Environment-variable and app.properties configuration.
  • 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 / assertFalse
  • assertEqual / assertNotEqual
  • assertGreater / assertLess
  • assertIn / assertNotIn
  • assertRegex
  • assertInTolerance
  • assertInRange
  • skipAssert

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

budtestlibrary-1.0.3.tar.gz (45.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

budtestlibrary-1.0.3-py3-none-any.whl (35.6 kB view details)

Uploaded Python 3

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

Hashes for budtestlibrary-1.0.3.tar.gz
Algorithm Hash digest
SHA256 436cd61bd87cf8f79e4c7336316f40a8e9ce974a8f3fe8ac46464c40191905d8
MD5 7dc4fb7bc780afaf80222120c3065532
BLAKE2b-256 7bcaf7e65d78b478f7eaab3b525e63d9fa7c8e76a719b7e9a9094c383e1cf895

See more details on using hashes here.

Provenance

The following attestation bundles were made for budtestlibrary-1.0.3.tar.gz:

Publisher: ci-cd.yml on MbedLabs/bud-test-library

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for budtestlibrary-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 7b8f02b5ee084b621789cdcfe7c91eacdc925b1201182a60e99163188f7b7464
MD5 c2fc746748df5fa821dd58a32ae9f6a9
BLAKE2b-256 b173494262583aa7beb253a9fafb2151db3a08dfb1d727e6493566f976fc1ebe

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page