Files
esphome/tests/components
J. Nick Koston 59065c71a8 [sx1509] Add interrupt pin support
Add optional interrupt_pin configuration to eliminate I2C polling
for GPIO reads. When configured, the component disables its loop
and only reads the I2C bus when the interrupt fires, matching
the pattern used by PCF8574, PCA9554, and other GPIO expanders.

When keypad mode is active, the loop continues running for key
scanning regardless of interrupt configuration.
2026-04-09 13:28:35 -10:00
..
2026-04-06 21:59:05 -10:00
2026-01-29 22:48:16 -05:00
2025-09-26 08:53:21 +12:00
2025-11-23 21:25:24 -06:00
2026-04-09 13:28:35 -10:00
2025-11-03 18:29:30 -06:00

How to write C++ ESPHome unit tests

  1. Locate the folder with your component or create a new one with the same name as the component.
  2. Write the tests. You can add as many .cpp and .h files as you need to organize your tests.

IMPORTANT: wrap all your testing code in a unique namespace to avoid linker collisions when compiling testing binaries that combine many components. By convention, this unique namespace is esphome::component::testing (where "component" is the component under test), for example: esphome::uart::testing.

Platform components

For components that expose to a platform component, create a folder under your component test folder with the platform component name, e.g. binary_sensor and include the relevant .cpp and .h test files there.

Override component code generation for testing

During C++ test builds, to_code is suppressed for every component by default — most components do not need to generate configuration code for a unit test binary.

Manifest overrides

If your component needs to customise code generation behavior for testing — for example to re-enable to_code, supply a lightweight stub, add a test-only dependency, or change any other manifest attribute — create an __init__.py in your component's test directory and define override_manifest:

Top-level component (tests/components/<component>/__init__.py):

from tests.testing_helpers import ComponentManifestOverride

def override_manifest(manifest: ComponentManifestOverride) -> None:
    # Re-enable the component's own to_code (needed when the component must
    # emit C++ setup code that the test binary depends on at link time).
    manifest.enable_codegen()

Or supply a lightweight stub instead of the real to_code:

from tests.testing_helpers import ComponentManifestOverride

def override_manifest(manifest: ComponentManifestOverride) -> None:
    async def to_code_testing(config):
        # Only emit what the C++ tests actually need
        pass

    manifest.to_code = to_code_testing
    manifest.dependencies = manifest.dependencies + ["some_test_only_dep"]

Platform component (tests/components/<component>/<domain>/__init__.py, e.g. tests/components/my_sensor/sensor/__init__.py):

from tests.testing_helpers import ComponentManifestOverride

def override_manifest(manifest: ComponentManifestOverride) -> None:
    manifest.enable_codegen()

override_manifest receives a ComponentManifestOverride that wraps the real manifest. Attribute assignments store an override; reads fall back to the real manifest when no override is present.

Key methods:

Method Effect
manifest.enable_codegen() Remove the to_code suppression, re-enabling code generation
manifest.restore() Clear all overrides, reverting every attribute to the original

The function is called after to_code has already been set to None, so calling enable_codegen() is a deliberate opt-in.

Running component unit tests

(from the repository root)

./script/cpp_unit_test.py component1 component2 ...

The above will compile and run the provided components and their tests.

To run all tests, you can invoke cpp_unit_test.py with the special --all flag:

./script/cpp_unit_test.py --all

To run a specific test suite, you can provide a Google Test filter:

GTEST_FILTER='UART*' ./script/cpp_unit_test.py uart modbus

The process will return 0 for success or nonzero for failure. In case of failure, the errors will be printed out to the console.