diff --git a/docs/en/api-guides/unit-tests.rst b/docs/en/api-guides/unit-tests.rst index bfc1000e3..a452ac047 100644 --- a/docs/en/api-guides/unit-tests.rst +++ b/docs/en/api-guides/unit-tests.rst @@ -25,7 +25,7 @@ Tests are added in a function in the C file as follows: The first argument is a descriptive name for the test, the second argument is an identifier in square brackets. Identifiers are used to group related test, or tests with specific properties. -.. note:: +.. note:: There is no need to add a main function with ``UNITY_BEGIN()`` and ``​UNITY_END()`` in each test case. ``unity_platform.c`` will run ``UNITY_BEGIN()`` autonomously, and run the test cases, then call ``​UNITY_END()``. The ``test`` subdirectory should contain a :ref:`component CMakeLists.txt `, since they are themselves, components. ESP-IDF uses the ``unity`` test framework and should be specified as a requirement for the component. Normally, components :ref:`should list their sources manually `; for component tests however, this requirement is relaxed and the use of the ``SRC_DIRS`` argument in ``idf_component_register`` is advised. @@ -119,6 +119,70 @@ To support this, we can define multi-stage test cases, to group a set of test fu Multi-stage test cases present a group of test functions to users. It needs user interactions (select cases and select different stages) to run the case. +Tests For Different Targets +--------------------------- + +Some tests (especially those related to hardware) cannot run on all targets. Below is a guide how +to make your unit tests run on only specified targets. + +1. Wrap your test code by ``!(TEMPORARY_)DISABLED_FOR_TARGETS()`` macros and place them either in + the original test file, or sepeprate the code into files grouped by functions, but make sure all + these files will be processed by the compiler. E.g.: :: + + #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32, ESP8266) + TEST_CASE("a test that is not ready for esp32 and esp8266 yet", "[]") + { + } + #endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32, ESP8266) + + Once you need one of the tests to be compiled on a specified target, just modify the targets + in the disabled list. It's more encouraged to use some general conception that can be + described in ``soc_caps.h`` to control the disabling of tests. If this is done but some of the + tests are not ready yet, use both of them (and remove ``!(TEMPORARY_)DISABLED_FOR_TARGETS()`` + later). E.g.: :: + + #if SOC_SDIO_SLAVE_SUPPORTED + #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP64) + TEST_CASE("a sdio slave tests that is not ready for esp64 yet", "[sdio_slave]") + { + //available for esp32 now, and will be available for esp64 in the future + } + #endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP64) + #endif //SOC_SDIO_SLAVE_SUPPORTED + +2. For test code that you are 100% for sure that will not be supported (e.g. no peripheral at + all), use ``DISABLED_FOR_TARGETS``; for test code that should be disabled temporarily, or due to + lack of runners, etc., use ``TEMPORARY_DISABLED_FOR_TARGETS``. + +Some old ways of disabling unit tests for targets, that have obvious disadvantages, are deprecated: + +- DON'T put the test code under ``test/target`` folder and use CMakeLists.txt to choose one of the + target folder. This is prevented because test code is more likely to be reused than the + implementations. If you put something into ``test/esp32`` just to avoid building it on esp32s2, + it's hard to make the code tidy if you want to enable the test again on esp32s3. + +- DON'T use ``CONFIG_IDF_TARGET_xxx`` macros to disable the test items any more. This makes it + harder to track disabled tests and enable them again. Also, a black-list style ``#if !disabled`` + is preferred to white-list style ``#if CONFIG_IDF_TARGET_xxx``, since you will not silently + disable cases when new targets are added in the future. But for test implementations, it's + allowed to use ``#if CONFIG_IDF_TARGET_xxx`` to pick one of the implementation code. + + - Test item: some items that will be performed on some targets, but skipped on other + targets. E.g. + + There are three test items SD 1-bit, SD 4-bit and SDSPI. For ESP32S2, which doesn't have + SD host, among the tests only SDSPI is enabled on ESP32S2. + + - Test implementation: some code will always happen, but in different ways. E.g. + + There is no SDIO PKT_LEN register on ESP8266. If you want to get the length from the slave + as a step in the test process, you can have different implementation code protected by + ``#if CONFIG_IDF_TARGET_`` reading in different ways. + + But please avoid using ``#else`` macro. When new target is added, the test case will fail at + building stage, so that the maintainer will be aware of this, and choose one of the + implementations explicitly. + Building Unit Test App ---------------------- diff --git a/docs/zh_CN/api-guides/unit-tests.rst b/docs/zh_CN/api-guides/unit-tests.rst index 0145544df..24e21138c 100644 --- a/docs/zh_CN/api-guides/unit-tests.rst +++ b/docs/zh_CN/api-guides/unit-tests.rst @@ -34,7 +34,7 @@ C 文件可以包含多个测试用例。测试文件的名字要以 “test” ``test`` 子目录应包含 :ref:`组件 CMakeLists.txt `,因为他们本身就是一种组件。ESP-IDF 使用了 ``unity`` 测试框架,需要将其指定为组件的依赖项。通常,组件 -:ref:`需要手动指定待编译的源文件 `;但是,对于测试组件来说,这个要求被放宽为仅建议将参数 ``SRC_DIRS`` 用于 ``idf_component_register``。 +:ref:`需要手动指定待编译的源文件 `;但是,对于测试组件来说,这个要求被放宽为仅建议将参数 ``SRC_DIRS`` 用于 ``idf_component_register``。 总的来说,``test`` 子目录下最小的 CMakeLists.txt 文件可能如下所示: @@ -137,6 +137,48 @@ DUT2(slave)终端: 多阶段测试用例向用户呈现了一组测试函数,它需要用户进行交互(选择用例并选择不同的阶段)来运行。 +应用于不同芯片的单元测试 +------------------------ + +某些测试(尤其与硬件相关的)无法在所有的芯片上执行。请参照本节让你的单元测试只在其中一部分芯片上执行。 + +1. 使用宏 ``!(TEMPORARY_)DISABLED_FOR_TARGETS()`` 保护你的测试代码,并将其放于原来的位置,或者放在另外准备以功能区分的文件。但请确保所有这些文件都会被编译器处理到。例: :: + + #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32, ESP8266) TEST_CASE("a test that is not ready for esp32 and esp8266 yet", "[]") + { + } + #endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32, ESP8266) + + 一旦你需要其中一个测试在某个芯片上被编译,只需要修改禁止的芯片列表。我们更鼓励使用一些通用的概念(能在 ``soc_caps.h`` 中被清楚描述)来禁止某些单元测试。如果你已经这样做,但有一些测试还没有在新的芯片版本中被调试通过,请同时使用上述两种方法,当调试完成后再移除 ``!(TEMPORARY_)DISABLED_FOR_TARGETS()`` 。例: :: + + #if SOC_SDIO_SLAVE_SUPPORTED + #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP64) + TEST_CASE("a sdio slave tests that is not ready for esp64 yet", "[sdio_slave]") + { + //available for esp32 now, and will be available for esp64 in the future + } + #endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP64) + #endif //SOC_SDIO_SLAVE_SUPPORTED + +2. 对于某些你绝对肯定不可能被支持的测试(例如,芯片根本没有该外设),使用 ``DISABLED_FOR_TARGETS`` 来禁止该测试;对于其他只是临时性需要关闭的(例如,没有 runner 资源等),使用 ``TEMPORARY_DISABLED_FOR_TARGETS`` 来暂时关闭该测试。 + +请勿继续使用一些旧的禁止单元测试在一些芯片上执行的做法,因为他们具有明显的坏处: + +- 请勿将测试代码放在 ``test/芯片版本`` 目录下面,然后用 CMakeLists.txt 来选择其中一个进行编译。这是因为测试代码比实现代码更容易被复用。如果你将一些代码放在 ``test/esp32`` 目录下来避免 esp32s2 芯片执行它,一旦你需要在新的芯片(比如 esp32s3 )中启用该测试,你会发现这种结构非常难以保持代码的整洁。 + +- 请勿继续使用 ``CONFIG_IDF_TARGET_xxx`` 宏来禁止某些测试在一些芯片上编译。这种 方法会让被禁止的测试项目难以追踪和重新打开。并且,相比于白名单式的 ``#if CONFIG_IDF_TARGET_xxx`` ,黑名单式的 ``#if !disabled`` 能避免新芯片引入时,这些测试被自动关闭。 + + 但对于用于测试的一些实现, ``#if CONFIG_IDF_TARGET_xxx`` 仍可用于给不同芯片版本选择实现代码。测试项目和测试实现区分如下: + + - 测试项目:某些你会在一些芯片上执行,而在另外一些上跳过的项目,例如: + + 有三个测试项目 SD 1-bit 、 SD 4-bit 和 SDSPI 。对于不支持 SD Host 外设的ESP32-S2 芯片,只有 SDSPI 一个项目需要被执行。 + + - 测试实现:某些代码永远会发生,但采取不同的做法。例如: + + ESP8266 芯片没有 SDIO_PKT_LEN 寄存器。如果在测试过程中需要获取从机准备好的数据长度,你可以用 ``#if CONFIG_IDF_TARGET_`` 宏来选择读取该长度的不同方法实现。 + + 但请注意避免使用 ``#else`` 宏。这样当新芯片被引入时,测试就会在编译阶段失败,提示维护者去显示选择一个正确的测试实现。 编译单元测试程序 ----------------