为什么要进行自动化测试?
以下是我们应该进行自动化测试的许多重要原因之一:
-
您可以更快地对代码进行增量更新。ROS 有数百个包,具有许多相互依赖关系,因此很难预见一个小变化可能引起的问题。如果您的更改通过了单元测试,您可以更有信心地认为您没有引入问题------或者至少问题不是您的错。
-
您可以更自信地重构代码。通过单元测试可以验证您在重构时没有引入任何错误。这让您摆脱了对变化的恐惧,获得了这种美妙的自由!
-
它导致更好的代码设计。单元测试迫使你编写代码,使其更容易测试。这通常意味着保持底层函数和框架分离,这是我们设计 ROS 代码的目标之一。
-
他们防止重复出现的错误(错误回归)。为你修复的每个错误编写单元测试是一个好习惯。事实上,在修复错误之前编写单元测试。这将帮助你精确地,甚至是确定性地重现错误,并更精确地理解问题所在。结果,你还将创建一个更好的补丁,然后可以使用回归测试来验证错误是否已修复。这样,如果代码在以后被修改,错误就不会意外地重新引入。这也意味着说服补丁审查员问题已解决,并且贡献质量很高会更容易。
-
其他人可以更容易地处理你的代码(自动文档形式)。当你进行更改时,很难判断你是否破坏了别人的代码。单元测试是其他开发人员验证其更改的工具。自动测试记录你的编码决策,并自动向其他开发人员传达其违规行为。因此,测试成为你的代码的文档------一种大多数时间不需要阅读的文档,当需要检查时,测试系统会准确指示需要阅读的内容(哪些测试失败)。通过编写自动测试,你使其他贡献者更快。这改善了整个 ROS 项目。
-
如果我们有自动化单元测试,成为 ROS 的贡献者会容易得多。对于新的外部开发人员来说,向您的组件做出贡献是非常困难的。当他们对代码进行更改时,通常是在盲目操作,依靠大量的猜测。通过提供自动化测试的工具,您可以帮助他们完成任务。他们会立即获得更改的反馈。这样更容易为项目做出贡献,新贡献者也更容易加入。此外,他们的首次贡献质量更高,从而减少了维护人员的工作量。这是双赢的局面!
-
自动测试简化了维护工作。特别是对于变化较慢的成熟软件包,主要需要更新到新的依赖项,自动测试套件有助于快速确定软件包是否仍然有效。这使得决定软件包是否仍然受支持变得更加容易。
-
自动测试放大了持续集成的价值。回归测试以及基于正常场景的需求测试,有助于为您的组件提供整体的自动化测试。您的组件在依赖的其他 API 演变过程中得到了更好的测试(CI 服务器将更好、更准确地告诉您代码中出现的问题)。
也许编写测试最重要的好处是测试使你成为一个好公民。测试从长远来看会影响质量。这是许多开源项目中广泛接受的做法。通过编写回归测试,你正在为 ROS 生态系统的长期质量做出贡献。
这一切都是免费的吗?
当然,天下没有免费的午餐。要获得测试的好处,必须进行一些投资。
-
您需要开发一个测试,这有时可能会很困难或昂贵。有时它也可能并非易事,因为测试应该是自动化的。如果您的测试涉及特殊硬件(不应该:尝试使用模拟、模拟硬件或将测试缩小到较小的软件问题)或需要外部环境,例如人类操作员,事情会变得特别棘手。
-
回归测试和其他自动测试需要维护。当组件的设计发生变化时,许多测试会失效(例如,它们不再编译,或抛出与 API 设计相关的运行时异常)。这些测试失败不仅是因为重新设计重新引入了错误,还因为它们需要更新到新的设计。偶尔,对于较大的重新设计,旧的回归测试应该被删除。
-
大量的测试可能需要很长时间才能运行,这会增加持续集成服务器的成本。
可用教程:
-
从命令行运行 ROS 2 测试
-
使用 GTest 编写 C++ 基本测试
-
用 Python 编写基本测试
从命令行运行 ROS 2 测试
构建并运行你的测试
要编译和运行测试,只需从 colcon
运行测试动词 https://colcon.readthedocs.io/en/released/reference/verb/test.html 。
apache
colcon test --ctest-args tests [package_selection_args]
(其中 package_selection_args
是 colcon
的可选包选择参数,用于限制构建和运行的包)
在测试之前获取工作区应该是不必要的。 colcon test
确保测试在正确的环境中运行,能够访问它们的依赖项等。
检查测试结果
要查看结果,只需从 colcon
运行 test-result 动词。https://colcon.readthedocs.io/en/released/reference/verb/test-result.html
apache
colcon test-result --all
要查看确切的失败测试用例,请使用 --verbose
标志:
apache
colcon test-result --all --verbose
使用 GDB 调试测试
有关使用 GDB 调试测试的详细指南,请参阅 GDB 教程 https://docs.ros.org/en/jazzy/How-To-Guides/Getting-Backtraces-in-ROS-2.html 。
使用 GTest 编写 C++ 基本测试
起点:我们假设您已经设置了一个基本的 ament_cmake 包,并且您想要添加一些测试。
在本教程中,我们将使用 gtest。https://google.github.io/googletest/primer.html
程序包设置
源代码
我们将从一个名为 test/tutorial_test.cpp
的文件中的代码开始
cpp
#include <gtest/gtest.h>
TEST(package_name, a_first_test)
{
ASSERT_EQ(4, 2 + 2);
}
int main(int argc, char ** argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
package.xml
将以下行添加到 package.xml
xml
<test_depend>ament_cmake_gtest</test_depend>
CMakeLists.txt
ruby
if(BUILD_TESTING)
find_package(ament_cmake_gtest REQUIRED)
ament_add_gtest(${PROJECT_NAME}_tutorial_test test/tutorial_test.cpp)
target_include_directories(${PROJECT_NAME}_tutorial_test PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(${PROJECT_NAME}_tutorial_test name_of_local_library)
endif()
测试代码被包装在 if/endif
块中,以尽可能避免构建测试。 ament_add_gtest
的功能类似于 add_executable
,因此您需要像往常一样调用 target_include_directories
、 ament_target_dependencies
和 target_link_libraries
。
运行测试
请参阅有关如何从命令行运行测试 https://docs.ros.org/en/jazzy/Tutorials/Intermediate/Testing/CLI.html 的教程,以获取有关运行测试和检查测试结果的更多信息。
用 Python 编写基本测试
起点:我们假设您已经设置了一个基本的 ament_python 包,并且您想为其添加一些测试。
如果您使用 ament_cmake_python,请参阅 ament_cmake_python 文档以了解如何使测试可发现。测试内容和使用 colcon
的调用保持不变。
程序包设置
setup.py
您的 setup.py
必须在调用 setup(...)
时对 pytest
有测试依赖:
ini
tests_require=['pytest'],
测试文件和文件夹
您的测试代码需要放在包根目录中名为 tests
的文件夹中。
任何包含您要运行的测试的文件必须具有模式 test_FOO.py
,其中 FOO
可以替换为任何内容。
示例包布局:
java
awesome_ros_package/
awesome_ros_package/
__init__.py
fozzie.py
package.xml
setup.cfg
setup.py
tests/
test_init.py
test_copyright.py
test_fozzie.py
测试内容
您现在可以尽情编写测试了。关于 pytest 有很多资源,但简而言之,您可以编写带有 test_
前缀的函数,并包含您想要的任何断言语句。
python
def test_math():
assert 2 + 2 == 5 # This should fail for most mathematical systems
运行测试
请参阅有关如何从命令行运行测试的教程,以获取有关运行测试和检查测试结果的更多信息。
特殊命令
除了标准的 colcon 测试命令外,您还可以使用 --pytest-args
标志从命令行向 pytest
框架指定参数。例如,您可以指定要运行的函数名称。
nginx
colcon test --packages-select <name-of-pkg> --pytest-args -k name_of_the_test_function
要在运行测试时查看 pytest 输出,请使用以下标志:
bash
colcon test --event-handlers console_cohesion+