smithery.ai

ROS2 Testing

ROS2 test strategies and patterns with Clean Architecture (Python & C++)

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 4,134 B
  • docs SUMMARY.md 92 B

History

  1. First recorded snapshot · 1 installs

SKILL.md

ROS2 Testing Skill

This skill provides test strategies for ROS2 applications adhering to Clean Architecture principles, covering Unit, Integration, and E2E tests in both Python and C++.

Test Pyramid

        /\
       /  \  E2E Tests (Launch Tests / System Tests)
      /----\
     /      \  Integration Tests (Node / Component Tests)
    /--------\
   /          \  Unit Tests (Domain / Application Logic)
  /--------------\

Directory Structure

tests/
├── unit/
│   ├── domain/
│   └── application/
├── integration/
│   └── ros2/
└── e2e/
    └── launch_tests/

Python Testing

1. Unit Tests (Domain Layer)

See the previous version for Python Unit Test examples. They remain valid as domain logic is pure Python.

2. Integration Tests (Node Test)

# tests/integration/ros2/nodes/test_sensor_node.py
import pytest
import rclpy
from rclpy.node import Node
from std_msgs.msg import Float64

@pytest.fixture(scope='module')
def ros_context():
    rclpy.init()
    yield
    rclpy.shutdown()

@pytest.fixture
def test_node(ros_context):
    node = Node('test_helper')
    yield node
    node.destroy_node()

def test_sensor_integration(test_node):
    # Verify node behavior by subscribing/publishing
    pass

C++ Testing (GTest)

1. Unit Tests (Domain Layer)

// tests/unit/domain/use_cases/test_robot_controller.cpp
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "domain/use_cases/robot_controller.hpp"
#include "domain/entities/robot_state.hpp"

using namespace domain;
using ::testing::Return;

class MockRobotRepository : public repositories::IRobotRepository {
public:
    MOCK_METHOD(entities::RobotState, get_state, (), (override));
    MOCK_METHOD(void, set_mode, (entities::RobotMode), (override));
};

TEST(RobotControllerTest, StartFromIdle) {
    auto mock_repo = std::make_shared<MockRobotRepository>();
    use_cases::RobotControllerUseCase use_case(mock_repo);

    EXPECT_CALL(*mock_repo, get_state())
        .WillOnce(Return(entities::RobotState{entities::RobotMode::IDLE}));

    EXPECT_CALL(*mock_repo, set_mode(entities::RobotMode::ACTIVE));

    auto result = use_case.start();
    EXPECT_TRUE(result.success);
}

2. Integration Tests (Node/Component)

// tests/integration/ros2/test_sensor_node.cpp
#include <gtest/gtest.h>
#include <rclcpp/rclcpp.hpp>
#include "infrastructure/ros2/nodes/sensor_node.hpp"

class SensorNodeTest : public ::testing::Test {
protected:
    void SetUp() override {
        rclcpp::init(0, nullptr);
        node_ = std::make_shared<infrastructure::ros2::nodes::SensorNode>();
    }

    void TearDown() override {
        rclcpp::shutdown();
    }

    std::shared_ptr<infrastructure::ros2::nodes::SensorNode> node_;
};

TEST_F(SensorNodeTest, Initialization) {
    EXPECT_STREQ(node_->get_name(), "sensor_node");
}

3. Launch Tests (Python with GTest)

You can run GTest executables from launch files to perform system-level tests.

# tests/e2e/launch_tests/system_test.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
from launch_testing.actions import ReadyToTest

def generate_launch_description():
    # Launch system under test
    app_node = Node(package='my_robot', executable='main_node')

    # Launch GTest runner
    test_runner = Node(
        package='my_robot',
        executable='system_integration_test',
        output='screen'
    )

    return LaunchDescription([
        app_node,
        test_runner,
        ReadyToTest()
    ])

Best Practices

  • Mocking: Use unittest.mock for Python and gmock for C++.
  • Separation: Keep domain logic usage in unit tests strictly separate from ROS2 dependencies.
  • Fixtures: Use pytest.fixture and GTest SetUp/TearDown to manage ROS2 context (rclpy.init/shutdown).
  • Async Testing: For C++ integration tests, use rclcpp::spinsome or waitfor_future to handle async operations.