ros2 test 명령어 활용과 구성
ros2 test 명령어의 개요
ROS2 환경에서 테스트를 실행하고 확인하는 작업은 품질 관리 측면에서 매우 중요하다. 일반적으로 ROS2 기반 프로젝트를 빌드하거나 패키지를 배포하기 전에 유닛 테스트(Unit Test), 통합 테스트(Integration Test), 시스템 테스트(System Test) 등이 고루 수행되어야 한다. 이러한 테스트들을 손쉽게 실행할 수 있도록 도와주는 명령어가 바로 ros2 test이다.
ros2 test는 ROS2 패키지 내부에 정의된 테스트 파일들을 자동으로 검색하고, 적절한 테스트 러너(Test Runner)를 호출하여 테스트를 실행한다. 이 과정에서 기존의 ROS2 인프라를 그대로 활용하므로, 메시지와 서비스 인터페이스 정의, ROS2 launch 파일 등을 통합적으로 테스트하기에 적합하다.
ros2 test 명령어와 colcon test의 비교
ROS2 패키지 관리 및 빌드 툴로 자주 활용되는 colcon은, colcon test를 통해 전체 워크스페이스(workspace)에 대한 테스트를 일괄 수행한다. 반면 ros2 test는 ROS2 CLI(Command Line Interface)에서 제공되는 하위 명령어로서, 특정 패키지나 특정 테스트 대상만을 직접 선택하여 수행하기에 유리하다.
colcon test
장점: 워크스페이스 내 여러 패키지를 일괄 테스트
단점: 특정 패키지만 따로 테스트하기 어렵고, 전역 설정이 필요
ros2 test
장점: 단일 패키지나 테스트 대상만을 빠르게 실행
단점: 워크스페이스 전반에 걸친 일괄 테스트에는 적합하지 않을 수 있음
두 명령어는 상호 보완적인 관계에 있다. CI(Continuous Integration) 파이프라인 등에서는 전체 테스트를 돌리기 위해 colcon test를 쓰고, 로컬 개발 환경에서는 의도적으로 특정 테스트를 여러 번 반복 실행하기 위해 ros2 test를 사용하는 방식으로 나누어 활용할 수 있다.
ros2 test 기본 사용법
ROS2 패키지에서 테스트를 실행하기 위해서는 우선 해당 패키지의 CMakeLists.txt(CMake 빌드 시스템 사용 시) 혹은 setup.py(Python 패키지 사용 시)에 테스트를 정의해야 한다. 이후 아래와 같이 ros2 test 명령어를 통해 테스트를 호출한다.
# 특정 패키지의 테스트를 모두 실행
ros2 test <package_name>
# 특정 패키지 내부의 개별 테스트 파일만 실행
ros2 test <package_name> --test-file <테스트파일 경로>
# 결과 로그 또는 XML 보고서 생성 여부를 지정
ros2 test <package_name> --test-file <테스트파일 경로> --coverage위처럼 --test-file 옵션을 이용하면, 패키지에 등록된 여러 테스트 중에서 특정 테스트 파일만 선택적으로 실행할 수 있다. 또한 --coverage 옵션(혹은 다른 인자)을 통해 커버리지(coverage) 보고서를 자동 생성하도록 설정할 수도 있다.
테스트 관련 일반적인 디렉터리 구조
대부분의 ROS2 패키지는 다음과 같은 구조를 갖는다.
test/디렉터리는 테스트 코드를 저장하는 곳이다.CMakeLists.txt에는 테스트를 빌드하고 실행하도록 설정하는 명령어(add_rostest,ament_add_gtest등)를 기재한다.실제 테스트 소스 파일(
test_something.cpp등)은 단위 테스트를 포함할 수도 있고, ROS2 노드/토픽/서비스 연동 테스트를 포함할 수도 있다.
CMake 연동과 add_rostest
ROS2 테스트를 작성할 때 자주 쓰이는 매크로 중 하나가 add_rostest이다. ROS1 시절부터 제공되던 rostest 확장 기능을 ROS2 환경에서도 활용할 수 있도록 일부 유지하고 있다. 다만 ROS2에서는 ament_cmake를 사용하는 경우가 많으므로, add_rostest_gtest 등 확장형 매크로가 적용되기도 한다.
위와 같은 CMake 설정을 통해, test_something.cpp 파일에 정의된 테스트를 빌드와 동시에 등록할 수 있다. 이렇게 등록된 테스트는 colcon test나 ros2 test <package_name> 명령어로 실행할 수 있다.
Python 테스트(ament_cmake_pytest)와 ros2 test 연동
ROS2 패키지에서 테스트를 작성할 때 C++만 활용하는 것은 아니다. Python 기반 노드나 스크립트를 테스트하기 위해서는 보통 ament_cmake_python 또는 ament_python 빌드 유형을 적용하고, 그 위에 pytest와 연동하는 방식으로 구성한다. 이를 위해 setup.py와 package.xml에 필요한 의존성을 명시하고, CMakeLists.txt에서 테스트를 등록할 수 있다.
아래는 Python 테스트를 위한 전형적인 설정 예시이다.
ament_add_pytest_test(test_name script.py ...)구문을 이용하면, 자동으로pytest를 통해 해당 스크립트를 테스트로 등록한다.ros2 test명령어로 실행할 때, C++ 테스트와 마찬가지로 동일한 CLI 인터페이스가 적용된다.
ros2 test와 커버리지(coverage) 측정
대규모 프로젝트에서 품질 관리를 수행할 때, 커버리지 분석이 중요한 지표로 활용된다.
스테이트먼트 커버리지(Statement Coverage): 코드 내 개별 실행문(Statement)이 실제 테스트에서 실행되었는지 확인
분기 커버리지(Branch Coverage): if, switch 등으로 분기된 로직의 각 분기가 테스트에서 수행되었는지 확인
ROS2와 CMake, 그리고 gcov(혹은 llvm-cov) 등을 조합하면 손쉽게 커버리지 측정이 가능하다. 이를 자동화하기 위해 ros2 test 실행 시 특정 옵션이나 환경 변수를 설정해 두면 좋다.
커버리지 옵션은 ROS2 CLI에서 직접 지원하지 않을 수도 있으나, 패키지 내 스크립트나 CI 설정에서 gcov 연동을 해두면 원하는 시점에 커버리지 리포트(HTML 또는 XML)를 생성할 수 있다.
CMake 설정 예시:
위와 같이 -DCOVERAGE=ON 옵션을 주어 빌드하면, gcov 관련 플래그가 추가되어 커버리지 데이터가 생성된다. 이후 ros2 test <package_name>를 실행한 뒤, gcov 또는 lcov 명령어로 최종 보고서를 만들 수 있다.
ros2 test의 고급 옵션
ros2 test 명령어에는 몇 가지 추가적인 옵션들이 제공될 수 있다. 버전에 따라 지원되는 범위가 상이할 수 있으나, 대표적으로 다음과 같은 옵션이 존재한다.
--test-file <file>: 특정 테스트 파일만 실행--launch-file <launch_file>: 테스트용 ROS2 launch 파일 실행 (일부 버전에서 지원)--abort-on-error: 테스트 오류 발생 시 즉시 중단--package-select <package_name>: 여러 패키지 중 특정 패키지만 선택 실행 (단, 버전에 따라 상이)
이 외에도 비동기 실행, 병렬 테스트 등의 기능을 조합하여, 대규모 프로젝트를 빠르고 유연하게 테스트할 수 있다.
ros2 test와 launch 파일을 통한 통합 테스트
ROS2에서는 노드와 토픽, 서비스 등 다양한 요소가 상호작용하는 통합 테스트가 필요하다. 이를 위해 rostest(ROS1 기준)와 유사하게 launch 파일을 통한 테스트가 가능하다.
launch_testing: ROS2에서 공식적으로 제공되는 launch 기반 테스트 지원 라이브러리
ros2 test --launch-file 옵션 또는
colcon test실행 시 launch_testing 연동노드 실행과 동시에 테스트 코드(또는 테스트 노드)를 자동 실행
예시 코드(test_something_launch.py):
위와 같이 launch_testing 프레임워크와 pytest를 조합하면, 노드 실행과 테스트 코드 실행을 한 번에 제어할 수 있다.
mermaid를 활용한 ros2 test 흐름
테스트 실행 과정을 시각화하면 다음과 같다.
위 시퀀스 다이어그램에서 ros2_test는 실제 ROS2 CLI 엔트리 포인트이고, 내부적으로 TestRunner(C++, Python, launch 등 다양한 러너)들이 동작하여 결과를 Results에 기록한 후 최종 요약을 출력한다.
병렬(Parallel) 테스트 실행
ROS2 패키지의 테스트 스위트가 방대해지면, 테스트에 소요되는 시간이 점점 길어지는 문제가 발생한다. 이때 병렬로 테스트를 실행하여 전체 테스트 시간을 단축할 수 있다. ros2 test 명령어 자체가 직접 병렬 옵션을 제공하지는 않더라도, 아래와 같은 방법들을 통해 다중 코어를 활용할 수 있다.
colcon test - —executor 옵션:
colcon test명령에--executor옵션이나--parallel-workers옵션을 지정하면, 내부적으로 여러 테스트를 병렬로 실행한다.이 경우,
ros2 test <package>를 직접 호출하기보다는colcon test가 알아서ros2 test와 유사한 형태로 각 패키지 테스트를 병렬로 수행한다.Linux parallel 유틸리티: 개발 환경에서 단순히 여러 명령을 동시에 실행하고 싶다면
parallel(GNU Parallel) 툴을 쓸 수도 있다. 예컨대 여러 테스트 파일을 나열하고,parallel을 통해 각 테스트를 동시에 호출할 수 있다.launch_testing 병렬 실행: 통합 테스트를
launch_testing으로 구성한 경우, 내부적으로 서브 테스트들이 병렬로 동작하게 만들 수도 있다. 이 방식은 복합 노드 실행 시 경합 상태(Race Condition)를 고려해야 하므로 주의가 필요하다.
환경 변수와 ros2 test
테스트 실행 시 환경 변수(Environment Variable)를 활용하는 방법도 있다. 예컨대 ROS2 관련 환경 변수(예: $ROS_DOMAIN_ID), 로깅 수준(예: $RCUTILS_CONSOLE_OUTPUT_FORMAT), 또는 테스트 전용 커스텀 환경 변수를 세팅해 두면 테스트 동작을 세밀하게 제어할 수 있다.
또한 CMakeLists.txt나 launch 파일에서 테스트 실행 시 필요한 환경 변수를 미리 세팅할 수도 있다.
이처럼 시스템 환경을 조정하여, 테스트 시나리오에 따라 ROS2의 동작을 가볍게 변경하거나, 테스트 의존성을 가상화(virtualization)하는 것이 가능하다.
테스트 결과와 로그 분석
ROS2 테스트를 실행하면 테스트 결과와 로그가 생성된다. 보통 결과 파일은 build/<package_name>/test_results/<package_name>/ 디렉터리에 저장된다(빌드 툴체인 설정에 따라 달라질 수 있음). 파일 형식은 XML 형태의 JUnit 호환 결과물이거나, GTest로부터 출력된 텍스트 로그가 될 수 있다.
XML(JUnit) 로그: CI 서버(Jenkins, GitLab CI 등)에서 테스트 결과를 시각화하고 집계할 때 유용
stdout 로그: GTest나 pytest가 직접 표시하는 콘솔 출력
ros2 test 실행 후 아래처럼 출력 디렉터리를 확인하여 로그와 XML 파일을 살펴볼 수 있다.
이 로그 파일들은 실패한 테스트 케이스, 에러 메시지, 테스트 실행 시간 등의 정보를 담고 있다. CI 통합 시에는 이 경로를 CI 툴과 연결하여 자동으로 결과를 수집, 대시보드 형태로 가공할 수 있다.
Debug 모드에서 테스트 수행
ROS2 프로젝트의 테스트가 실패하거나 크래시(Crash)가 발생했을 때, 문제를 디버깅(주로 C++ 기준 GDB 또는 LLDB 사용)하고 싶을 수 있다. 일반적인 방법은 다음과 같다.
Debug 빌드로 재컴파일:
테스트 바이너리를 직접 디버거로 실행: ros2 test를 통해 실행하는 대신, 내부적으로 등록된 테스트 실행 파일을 직접 찾아 디버거로 구동한다. 예시:
런치 테스트(launch_testing) 디버그: launch 파일을 통한 테스트에서는, 실제 노드 실행 커맨드를 gdb로 감싼다. 예를 들어:
이렇게 하면 테스트 동작 중 노드가 디버거 환경에서 구동되어, 크래시 시점을 추적할 수 있다.
ros2 test와 ament_lint
테스트는 단순히 기능 동작 확인뿐 아니라 코드 품질 검사(Lint)도 중요한 영역이다. ROS2의 ament_lint 패키지들은 아래와 같은 검사 항목을 제공한다.
ament_lint_auto: 여러 린트 규칙들을 자동으로 등록ament_cpplint: C++ 스타일 가이드 준수 여부 검사ament_flake8: Python 스타일 가이드 준수 여부 검사ament_xmllint: XML 형식 검사 (package.xml 등)
이러한 검사도 colcon test나 ros2 test 시 함께 실행할 수 있다. 보통 CMake 설정에서 다음과 같이 작성한다.
이렇게 설정해두면, colcon test를 실행할 때 자동으로 린트 검사 결과가 나오며, ros2 test <package>로도 린트 스크립트를 호출 가능하다.
매개변수화(Parameterized) 테스트 기법
복잡한 로직이나 다양한 입력값에 대해 반복적으로 테스트를 수행해야 할 때는 매개변수화 테스트(Parameterized Test)가 유용하다. GTest(C++), pytest(Python) 모두 매개변수화 기능을 제공하므로, ROS2 테스트에서도 이를 적극 활용할 수 있다.
C++ (GTest)에서의 Parameterized Test 예시
아래는 GTest를 활용한 기본적인 매개변수화 테스트 코드 예시이다.
TestWithParam<T>구조를 상속받아 테스트를 작성한다.INSTANTIATE_TEST_SUITE_P를 통해 여러 입력값(1, 2, 3)을 지정하면, 동일 테스트 로직이 각각의 값에 대해 반복 수행된다.$ ros2 test my_package명령어를 통해 수행되며, 결과 보고서에도 각 케이스별 성공/실패 여부가 표시된다.
Python (pytest)에서의 Parameterized Test 예시
pytest는 @pytest.mark.parametrize 데코레이터를 이용해 매개변수화 테스트를 작성할 수 있다.
pytest.mark.parametrize의 리스트 형태로 다양한 케이스를 정의한다.$ ros2 test my_python_package명령어를 쓰면, 각각의 파라미터에 대해 테스트가 독립적으로 실행된다.
Mocking과 Stubbing
ROS2 노드가 메시지를 발행하거나 서비스를 호출할 때, 실제 환경(예: 센서, 로봇 하드웨어 등)과 연결하지 않고 Mock 혹은 Stub을 적용하여 테스트를 진행하는 방식을 사용할 수 있다.
Mocking: 대상 객체(함수, 메서드 등)의 행위를 가짜로 구현하여 동작을 재정의
Stubbing: 외부 의존성을 최소화하기 위해 가짜 응답만 반환하는 방식
C++ 예시
Google Test와 Google Mock을 같이 사용하면 다음과 같은 구조를 구성할 수 있다.
위 예시는 ROS2 노드 내부 로직을 간접 호출하는 상황에서, 해당 노드가 사용하는 인터페이스(서비스, 하드웨어 드라이버 등)를 Mock 객체로 치환해 테스트하는 방법을 보여준다.
Python 예시
Python에서는 unittest.mock 모듈을 활용할 수 있다.
ROS2 환경에서 실제 토픽 발행, 서비스 호출 등에 대해서도 Mocking이 가능하지만, 이를 위해서는 rclpy 또는 rclcpp 레벨에서 분리된 인터페이스를 만들어 주입(Dependency Injection)하는 구조가 필요할 수 있다.
Fuzz Testing과 Property-based Testing
테스트 자동화 기법 중 하나로, 예상하지 못한 무작위 입력을 주어 소프트웨어의 예외 상황을 찾아내는 Fuzz Testing 혹은 Property-based Testing(Ex: Hypothesis, RapidCheck 등)도 활용될 수 있다.
Fuzz Testing: 비정형적이고 무작위로 생성된 데이터를 입력값으로 제공하여 프로그램 충돌, 메모리 오버플로 등 버그를 찾아내는 방법
Property-based Testing: 단순히 입력-출력의 일치 여부를 확인하기보다는, 입력이 만족해야 할 (또는 출력이 보장해야 할) 여러 가지 속성(Property)을 정의해두고 무작위 입력을 통해 그 속성을 검증
ROS2 환경에서 이러한 기법을 사용하는 경우, 토픽 메시지의 무작위 데이터, 서비스 호출 파라미터의 무작위 조합 등을 통한 스트레스 테스트 형태로 확장할 수 있다.
CI/CD 파이프라인에서의 ros2 test
실무 프로젝트에서는 지속적 통합/배포(CI/CD) 파이프라인과 결합해, 코드를 푸시할 때마다 자동으로 테스트를 수행하고 결과를 대시보드에 표시한다. 일반적인 워크플로우는 아래와 같다:
코드 푸시: Git 서버(예: GitLab, GitHub)로 개발자가 변경 사항 푸시
CI 스크립트 실행: Docker 컨테이너(또는 VM) 환경에서
colcon build와colcon test(또는ros2 test) 수행결과 수집: 테스트 로그(XML, HTML 등)를 CI 서버로 전송
보고서 및 알림: 성공/실패 여부, 커버리지 지표, 린트 결과 등을 시각화
예시 GitLab CI 설정(.gitlab-ci.yml):
이 구성대로라면 test_job이 실행될 때마다 자동으로 ROS2 테스트가 동작하고, 결과가 CI 시스템에 저장된다.
Last updated