# 单元测试
我们鼓励开发人员在开发的各个阶段编写单元测试,包括添加新功能、修复错误和重构。
PX4 提供了多种编写单元测试的方法:
- 单元测试 谷歌测试 (打开新窗口) ("GTest") - 仅有最小内部依赖关系的测试
- 使用 GTest 进行功能测试 - 依赖于参数和 uORB 消息的测试
- SITL 单元测试。这适用于需要以完整 SITL 运行的测试。这些测试运行速度更慢,调试也更困难,因此建议尽可能使用 GTest。
# 编写 GTest 单元测试
提示:一般来说,如果您需要访问高级 GTest 实用程序、STL 中的数据结构或需要链接到 参数
或 uorb
库,而应使用功能测试。
创建新单元测试的步骤如下:
- 单元测试应分为三个部分:设置、运行、检查结果。每个测试都应测试一个非常具体的行为或设置情况,这样如果测试失败,就能明显看出哪里出了问题。请尽可能遵循这些标准。
- 复制并重命名单元测试示例 态度控制测试 (打开新窗口) 到要测试的代码所在的目录。
- 将新文件添加到目录的
CMakeLists.txt
.它应该看起来像px4_add_unit_gtest(SRC MyNewUnitTest.cpp LINKLIBS <library_to_be_tested>)
- 添加所需的测试功能。这意味着要包含特定测试所需的头文件、添加新测试(每个测试都有独立名称)、设置逻辑、运行要测试的代码并验证其是否符合预期。
- 如果需要额外的依赖库,也应将它们添加到 CMakeLists 后的
链接库
如上图所示。
测试可通过 试验
之后,您将在 build/px4_sitl_test/unit-MyNewUnit
.它可以直接在调试器中运行。
# 编写 GTest 功能测试
当测试或被测组件依赖于参数、uORB 消息和/或高级 GTest 功能时,应使用 GTest 功能测试。此外,功能测试还可包含 STL 数据结构的本地使用(但要注意 macOS 和 Linux 等平台之间的差异)。
创建新功能测试的步骤如下:
- 一般来说(与单元测试类似),功能测试应分为三个部分:设置、运行、检查结果。每个测试都应测试一个非常具体的行为或设置情况,这样如果测试失败,就能明显看出问题所在。请尽可能遵循这些标准。
- 复制并重命名示例功能测试 参数测试 (打开新窗口) 到要测试的代码所在的目录。
- 将 ParameterTest 类重命名为更能代表测试代码的名称
- 将新文件添加到目录的
CMakeLists.txt
.它应该看起来像px4_add_functional_gtest(SRC MyNewFunctionalTest.cpp LINKLIBS <library_to_be_tested>)
- 添加所需的测试功能。这意味着要包含特定测试所需的头文件、添加新测试(每个测试都有独立名称)、设置测试逻辑、运行要测试的代码并验证其是否符合预期。
- 如果需要额外的依赖库,也应将它们添加到 CMakeLists 后的
链接库
如上图所示。
测试可通过 试验
之后,您将在 build/px4_sitl_test/functional-MyNewFunctional
.它可以直接在调试器中运行,但要注意使用 --gtest_filter=<regex>; (打开新窗口) 参数,因为 uORB 和参数库的某些部分不能完美地自我清理,如果多次设置,可能会导致未定义的行为。
# 编写 SITL 单元测试
当您特别需要飞行控制器的所有组件(驱动程序、时间等)时,应使用 SITL 单元测试。这些测试运行速度较慢(每个新模块需要 1 秒以上),调试起来也比较困难,因此一般只在必要时使用。
创建新 SITL 单元测试的步骤如下:
检查样本 统一班级 (打开新窗口).
内创建一个新的 .cpp 文件 试验 (打开新窗口) 用姓名 test_[description].cpp.
内 test_[description].cpp 包括基础 unittest-class
<unit_test.h>;
以及编写新功能测试所需的所有文件。内 test_[description].cpp 建班
[说明]测试
继承自单元测试
.内
[说明]测试
类声明的公共方法virtual bool run_tests()
.内
[说明]测试
类声明测试相关功能所需的所有私有方法 (test1()
,test2()
,...).内 test_[description].cpp 实施
run_tests()
方法,每个测试[1,2,...]都将在该方法中运行。内 test_[description].cpp实施各种测试。
在底部内 test_[description].cpp 宣布测试开始。
ut_declare_test_c(测试[描述], [说明]测试)
这里有一个模板:
#包括 <unit_test.h>; #包括 "[新功能].h"; ... 类 [说明]测试 : 公 单元测试 { 公: 虚拟 bool 运行测试(); 私人: bool 测试1(); bool 测试2(); ... }; bool [说明]测试::运行测试() { ut_run_test(测试1) ut_run_test(测试2) ... 返回 (测试失败 == 0); } bool [说明]测试::测试1() { ut_[单元测试函数之一的名称](... ut_[单元测试函数之一的名称](... ... 返回 真; } bool [说明]测试::测试2() { ut_[单元测试函数之一的名称](... ut_[单元测试函数之一的名称](... ... 返回 真; } ... ut_declare_test_c(测试[描述], [说明]测试)
请注意
ut_[单元测试函数名称]
对应于在 unit_test.h (打开新窗口).内 tests_main.h (打开新窗口) 定义新的测试:
外部 int 测试[描述](int 参数, 烧焦 *参数[]);
内 tests_main.c (打开新窗口) 添加说明名称、测试功能和选项:
... } 试验[] = { {... {"[描述]";, 测试[描述], 选项}, ... }
选项
可以是OPT_NOALLTEST
,OPT_NOJIGTEST
或0
如果在 px4 外壳中调用了这两个命令中的一个,就会被认为是"......":pxh>; 全部测试
或
pxh>; 试验夹具
如果测试有选项
OPT_NOALLTEST
则在调用全部测试
.对于OPT_NOJITEST
当命令试验夹具
被调用。选项0
意味着测试永远不会被排除,而这正是大多数开发人员希望使用的。添加测试
test_[description].cpp
到 CMakeLists.txt (打开新窗口).
# 在本地机器上进行测试
直接从 bash 运行 GTest 单元测试、GTest 功能测试和 SITL 单元测试的完整列表:
生产 试验
单个 GTest 测试二进制文件位于 build/px4_sitl_test/
目录,并可在大多数集成开发环境的调试器中直接运行。
使用此命令对ctest 名称使用正则表达式进行筛选,以便只运行部分测试:
生产 试验 TESTFILTER=<;regex 过滤器表达式>;
例如
make tests TESTFILTER=unit
仅运行 GTest 单元测试make tests TESTFILTER=sitl
仅运行模拟测试make tests TESTFILTER=Attitude
只运行态度控制
测试