Additional Markers

pytest-embedded provides additional markers to enhance testing functionality.

skip_if_soc

The skip_if_soc marker allows you to skip tests based on the soc_caps (System-on-Chip capabilities) of a target device. These capabilities are defined in esp-idf. For example, for the ESP32, you can find them in the header file soc_caps.h.

Use Case

Imagine you have multiple targets, such as [esp32, esp32c3, ..., esp32s4], but you want to skip tests for chips that do not support specific features.

The skip_if_soc marker simplifies this by allowing you to define conditions based on the soc_caps property of your chip. This enables dynamic filtering of targets without requiring manual, target-specific logic.

Examples

Here are some examples of how to use skip_if_soc with different conditions:

Condition 1: A boolean expression like SOC_ULP_SUPPORTED != 1 and SOC_UART_NUM != 3. This skips tests for chips that:

  • Do not support the low-power mode feature (SOC_ULP_SUPPORTED != 1).

  • And have a UART number other than 3 (SOC_UART_NUM != 3).

@pytest.mark.skip_if_soc("SOC_ULP_SUPPORTED != 1 and SOC_UART_NUM != 3")
@pytest.mark.parametrize("target", ["esp32", "esp32s2", "esp32c3"], indirect=True)
def test_template_first_condition():
    pass

Condition 2: A boolean expression like SOC_ULP_SUPPORTED != 1 or SOC_UART_NUM != 3. This skips tests for chips that:

  • Either do not support the low-power mode feature (SOC_ULP_SUPPORTED != 1).

  • Or have a UART number other than 3 (SOC_UART_NUM != 3).

@pytest.mark.skip_if_soc("SOC_ULP_SUPPORTED != 1 or SOC_UART_NUM != 3")
@pytest.mark.parametrize("target", ["esp32", "esp32s2", "esp32c3"], indirect=True)
def test_template_second_condition():
    pass

Condition 3: You can use a shortcut to apply this condition to all ESP-IDF supported targets (assuming IDF_PATH is set).

import pytest
from esp_bool_parser.constants import SUPPORTED_TARGETS

@pytest.mark.skip_if_soc("SOC_ULP_SUPPORTED != 1")
@pytest.mark.parametrize("target", SUPPORTED_TARGETS, indirect=True)
def test_template():
    pass

idf_parametrize

idf_parametrize is a wrapper around pytest.mark.parametrize that simplifies and extends string-based parameterization for tests. Using idf_parametrize makes testing parameters more flexible and easier to maintain.

Key Features:

  • Target Expansion: Automatically expands lists of supported targets, reducing redundancy in test definitions.

  • Markers: Use a marker as one of the parameters. If a marker is used, it should be the last parameter.

Use Cases

Target Extension

In scenarios where the supported targets are [esp32, esp32c3, esp32s3], idf_parametrize simplifies the process of creating parameterized tests by automatically expanding the target list.

By default, the values for SUPPORTED_TARGETS and PREVIEW_TARGETS are imported from:

from esp_bool_parser import PREVIEW_TARGETS, SUPPORTED_TARGETS

However, you can propagate custom values by using the following:

from pytest_embedded_idf.utils import supported_targets, preview_targets

supported_targets.set(CUSTOM_SUPPORT_TARGETS)
preview_targets.set(CUSTOM_SUPPORT_TARGETS)

Another way to override supported_targets and preview_targets is by using command-line arguments:

pytest --supported-targets esp32,esp32c3 --preview-targets esp32p4 ...

Example:

@idf_parametrize('target', [
    ('supported_targets'),
], indirect=True)
@idf_parametrize('config', [
    'default',
    'psram'
])
def test_st(dut: Dut) -> None:
    ...

Equivalent to:

@pytest.mark.parametrize('target', [
    'esp32',
    'esp32c3',
    'esp32s3'
], indirect=True)
@pytest.mark.parametrize('config', [
    'default',
    'psram'
])
def test_st(dut: Dut) -> None:
    ...

Resulting Parameters Matrix:

Target

Config

esp32

default

esp32c3

default

esp32s3

default

esp32

psram

esp32c3

psram

esp32s3

psram

Markers

You can also pass markers as the last item in a parameter tuple. If a test case does not need extra markers, you can omit them.

Example:

In ESP-IDF testing, environment markers specify which test runner should execute the test. For example:

  • generic: Tests that run on standard test runners.

  • sdcard: Tests that require an SD card runner.

  • usb_device: Tests that require a USB device runner.

@pytest.mark.generic
@idf_parametrize('config', [
    'defaults',
], indirect=['config'])
@idf_parametrize('target, markers', [
    ('esp32', (pytest.mark.usb_device,)),
    ('esp32c3',),
    ('esp32', (pytest.mark.sdcard,)),
], indirect=['target'])
def test_console(dut: Dut, config: str, target: str) -> None:
    ...

Resulting Parameters Matrix:

Target

Config

Markers

esp32

defaults

generic, usb_device

esp32c3

defaults

generic

esp32

defaults

generic, sdcard

Examples

Target with Config

Example:

@idf_parametrize('target, config', [
    ('esp32', 'release'),
    ('esp32c3', 'default'),
    ('supported_targets', 'psram'),
], indirect=True)
def test_st(dut: Dut) -> None:
    ...

Resulting Parameters Matrix:

Target

Config

esp32

release

esp32c3

default

esp32

psram

esp32c3

psram

esp32s3

psram

Supported Targets on Runners

Example:

@idf_parametrize('target, markers', [
    ('esp32', (pytest.mark.generic,)),
    ('esp32c3', (pytest.mark.sdcard,)),
    ('supported_targets', (pytest.mark.usb_device,)),
], indirect=True)
def test_st(dut: Dut) -> None:
    ...

Resulting Parameters Matrix:

Target

Markers

esp32

generic

esp32c3

sdcard

esp32

usb_device

esp32c3

usb_device

esp32s3

usb_device

Runner for All Tests

Example:

@pytest.mark.generic
@idf_parametrize('target, config', [
    ('esp32', 'release'),
    ('esp32c3', 'default'),
    ('supported_targets', 'psram'),
], indirect=True)
def test_st(dut: Dut) -> None:
    ...

Resulting Parameters Matrix:

Target

Config

Markers

esp32

release

generic

esp32c3

default

generic

esp32

psram

generic

esp32c3

psram

generic

esp32s3

psram

generic