!REDIRECT “https://docs.px4.io/master/zh/test_and_ci/unit_tests.html

单元测试

我们鼓励开发人员在开发的每个模块时编写单元测试,包括添加新功能,修复错误和重构。

PX4提供了以下几种编写单元测试的方法:

  1. 使用Google Test (“GTest”)进行单元测试 - 最小程度的内部依赖
  2. 使用GTest的功能测试 - 依赖parameters和 uORB和消息
  3. 软件在环(SITL)单元测试。 这些测试需要运行在完整的SITL环境中, 运行起来更慢,更难调试,所以建议尽可能使用GTest代替。

写一个GTest单元测试

Tip: 一般来说,如果你需要访问更高级的GTest工具、SITL的数据结构或者需要链接parametersuorb 库,你应改用功能测试。

创建新的单元测试步骤如下:

  1. 单元测试分成三个部分:设置、运行、检查结果。 每个单元测试都应该测试一个特定行为或设置案例,如果测试失败,则很明显你的测试代码有错误。 请尽可能遵循这些标准。
  2. Copy and rename the example unit test AttitudeControlTest to the directory the code to be tested is in.
  3. 将新文件到该目录的CMakeLists.txt文件中。 文件看起来像px4_add_unit_gtest(SRC MyNewUnitTest.cpp LINKLIBS <library_to_be_tested>)
  4. 添加你想要的测试功能。 这包括了添加所需的头文件、新测试(每个测试都应该有单独的名称),并加入相关逻辑,运行测试代码并验证其行为是否符合预期。
  5. 如果需要添加新的依赖库,只要在如上所说的CMakeLists文件中LINKLIBS后面加入库的名字。

可以通用 make tests命令来运行所有测试,然后在 build/px4_sitl_test/unit-MyNewUnit目录中找到二进行制文件。 也可以直接通过调试器中运行。

写一个GTest功能测试

当测试或测试的组件依赖参数、uORB 消息、或更高级的GTest功能的时候,应当使用GTest功能测试。 Additionally, functional tests can contain local usage of STL data structures (although be careful of platform differences between e.g. macOS and Linux).

创建一个新的功能测试步骤如下:

  1. 一般来说(与单元测试类似)功能测试应分为三个部分:设置,运行,检查结果。 每个测试都应该包括一个特定行为或是设置案例,如果测试失败,则很明显有错误。 请尽可能遵循这些标准。
  2. Copy and rename the example functional test ParameterTest to the directory the code to be tested is in.
  3. 将ParameterTest 重命名为更符合你正在测试的代码功能。
  4. 将新文件添加到目录里面的CMakeLists.txt。 文件内容看起来像 px4_add_functional_gtest(SRC MyNewFunctionalTest.cpp LINKLIBS <library_to_be_tested>)
  5. 添加你想要的测试功能。 这包括了,添加特定的头文件、新测试(每个测试都应该使用不同的命名),并设置相关逻辑,运行测试代码并验证是否符合预期。
  6. 如果需要添加新的依赖库,只要在如上所说的CMakeLists文件中LINKLIBS后面加入库的名字。

可以通用make tests命令来运行所有测试,然后在 build/px4_sitl_test/functional-MyNewFunctional目录中找到二进行制文件。 也可以直接通过调试器中运行。 It can be run directly in a debugger, however be careful to only run one test per executable invocation using the —gtest_filter=\ arguments, as some parts of the uORB and parameter libraries don’t clean themselves up perfectly and may result in undefined behavior if set up multiple times.

写一个软件在环(SITL)单元测试

当需要所有的飞行控制组件:驱动、时间或者更多时,应该SITL单元测试。 这些测试运行较慢(每个模块至少1秒+),同时难以测试,所以仅在必要时使用它们。

创建一个新的SITL单元测试步骤如下:

  1. Examine the sample Unittest-class.
  2. Create a new .cpp file within tests with name test_[description].cpp.
  3. test_[description].cpp 中包括基本 unittest-class<unit_test.h> 以及为新功能编写测试所需的所有文件。
  4. test_[description].cpp 中创建一个继承自 UnitTest 的类 [Description]Test
  5. [Description]Test 类中,声明公共方法 virtual bool run_tests()
  6. [Description]Test 类中,声明测试相关特征所需的所有私有方法(test1()test2(),…)。
  7. test_ [description].cpp 中实现 run_tests() 方法,其中将运行每个测试[1,2,…]。
  8. test_ [description].cpp 中,实现各种测试。
  9. test_ [description].cpp 的底部声明测试。

    1. ut_declare_test_c(test_[description], [Description]Test)

    下面是一个模板:

    1. #include <unit_test.h>
    2. #include "[new feature].h"
    3. ...
    4. class [Description]Test : public UnitTest
    5. {
    6. public:
    7. virtual bool run_tests();
    8. private:
    9. bool test1();
    10. bool test2();
    11. ...
    12. };
    13. bool [Description]Test::run_tests()
    14. {
    15. ut_run_test(test1)
    16. ut_run_test(test2)
    17. ...
    18. return (_tests_failed == 0);
    19. }
    20. bool [Description]Test::test1()
    21. {
    22. ut_[name of one of the unit test functions](...
    23. ut_[name of one of the unit test functions](...
    24. ...
    25. return true;
    26. }
    27. bool [Description]Test::test2()
    28. {
    29. ut_[name of one of the unit test functions](...
    30. ut_[name of one of the unit test functions](...
    31. ...
    32. return true;
    33. }
    34. ...
    35. ut_declare_test_c(test_[description], [Description]Test)

    Note that ut_[name of one of the unit test functions] corresponds to one of the unittest functions defined within unit_test.h.

  10. Within tests_main.h define the new test:

    1. extern int test_[description](int argc, char *argv[]);
  11. Within tests_main.c add description name, test function and option:

    ```cpp … } tests[] = { {… {“[description]”, test_[description], OPTION}, … }

    OPTION can be OPT_NOALLTEST,OPT_NOJIGTEST or 0 and is considered if within px4 shell one of the two commands are called:

    1. pxh> tests all

    or

    1. pxh> tests jig

    If a test has option OPT_NOALLTEST, then that test will be excluded when calling tests all. The same is true for OPT_NOJITEST when command test jig is called. 选项“0”表示从不排除测试,这是大多数开发人员想要使用的。

    1. Add the test test_[description].cpp to the CMakeLists.txt.
  1. ## 本地机器上的测试
  2. 运行完整的 GTest 单元测试列表 GTest 功能测试和 SITL 单元测试脚本:
  3. ```bash
  4. make tests

单独的 GTest 测试二进制文件处于build/px4_sitl_test/ 目录中,可以直接在大多数IDE的调试器中运行。

使用以下命令对ctest名称使用正则表达式对要运行的测试子集进行筛选:

  1. make tests TESTFILTER=<filter expression>

例如:

  • make tests TESTFILTER=unit only run GTest unit tests
  • make tests TESTFILTER=sitl only run simulation tests
  • make tests TESTFILTER=Attitude only run the AttitudeControl test