Addition 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 the esp-idf. For example, for the ESP32, you can reference them in the soc_caps.h file: soc_caps.h.

Use Case

Imagine you have multiple targets, such as [esp32, esp32c3, ..., esp32s4]. However, you may 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 the need for manual target-specific logic.

Examples

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

Condition 1: A boolean expression such as 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 such as 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. By using idf_parametrize, testing parameters becomes 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, put it as 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

Markers can also be combined for added flexibility. It must be placed in the last position. In this case, if some test cases do not have markers, you can skip their definition. Look at the example.

Example:

In IDF testing, an environment marker (marker) determines which test runner will execute a test. This enables tests to run on various runners, such as:

  • generic: Tests run on generic runners.

  • sdcard: Tests require an SD card runner.

  • usb_device: Tests 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, test_on: str) -> None:
  ...

Resulting Parameters Matrix:

Target

Markers

esp32

generic, usb_device

esp32c3

generic, sdcard

esp32

generic, sdcard

Examples

Target with Config

Example:

@idf_parametrize('target, config', [
    ('esp32', 'release'),
    ('esp32c3', 'default'),
    ('supported_target', '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 Target on Runners

Example:

@idf_parametrize('target, markers', [
    ('esp32', (pytest.mark.generic, )),
    ('esp32c3', (pytest.mark.sdcard, )),
    ('supported_target', (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_target', '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