Unit Tests
Key CMake snippet in adore_math/CMakeLists.txt:
The test/CMakeLists.txt then discovers test files and registers them:
Takeaways for library-style packages:
- Put tests in
test/. - Use a
test/CMakeLists.txtwithament_add_gtest. - Link tests against the library target (
${PROJECT_NAME}or similar). - Use
if(BUILD_TESTING)in the mainCMakeLists.txtand calladd_subdirectory(test).
Example: adore_math_conversions¶
Structure:
Key CMake snippet in adore_math_conversions/CMakeLists.txt:
Takeaways for node / conversion / ROS packages:
- Put tests in
test/and list them directly in the mainCMakeLists.txtor follow adore_decision_maker structure with separateCMakeLists.txtin test directory. - Use
ament_add_gtest(<test_target> test/<file>.cpp). - Link against
${PROJECT_NAME}(or the relevant library target).
How to write C++ tests¶
Both adore_math and adore_math_conversions use GoogleTest (GTest) via ament_cmake_gtest.
Test file template¶
A typical test file looks like this:
For more complex tests, you can use fixtures (TEST_F) or helpers:
Guidelines / expectations¶
-
Small and deterministic
-
Avoid non-deterministic behavior (time, randomness, global state).
-
If you measure performance, keep it short and deterministic – it still needs to pass in CI.
-
Round-trip & invariants
-
The conversion tests in
adore_math_conversionsuse round-trip checks:- convert C++ → ROS msg → C++ and compare the result.
-
For math utilities:
-
test symmetry, bounds, and known identities (e.g. degrees ↔ radians).
-
Naming
-
Prefer
TEST(Category, Behavior)whereCategoryis a class/module andBehavioris what you expect. -
File names generally mirror the unit under test:
distance_test.cpp,angle_test.cpp, … -
Include paths
-
Include public headers from
include/and avoid reaching intosrc/whenever possible. - If you really need internal details, consider adding a dedicated internal header rather than including
.cppdirectly.
Running tests¶
Running tests inside the dev container¶
The dev container has ROS and all build tools installed.
- Start or attach to the dev container:
-
Inside the container, from the repo root:
-
Run the whole test suite:
(This uses the same
Justfileand will runcolcon testinside the container.) -
Or run
colconmanually:
Running tests for a single package¶
From the repo root (host or dev container):
Replace adore_math with adore_math_conversions or any other package name.
Tips:
- You can pass multiple packages to
--packages-select:
Running a single test binary¶
Sometimes you just want to run one specific test executable directly (e.g., to debug with gdb).
After building and running colcon test at least once, the test binaries will be in the build/ directory. For example:
You can also attach a debugger:
Path details are managed by
ament_cmake_gtestandcolcon– if in doubt, inspect thebuild/<pkg>directory or re-runcolcon testto regenerate.
System tests¶
System tests are orchestrated separately:
please see System Tests
CI: tests + docs¶
For a local approximation of CI:
This:
- Uses the CI Docker image.
- Runs tests and documentation checks via
.docker/scripts/run_ci.sh.
Use this when you want a “what CI will do” check before pushing changes.
5. How to add tests to a new package¶
Step 1: Create test/ directory¶
Inside your package:
Step 2: Add GTest code¶
In test/my_feature_test.cpp:
Follow the patterns from adore_math and adore_math_conversions.
Step 3: Wire it up in CMake¶
Option A: test subdirectory (library-style, like adore_math)
CMakeLists.txt:
test/CMakeLists.txt (very similar to adore_math):
Option B: direct registration (like adore_math_conversions)
CMakeLists.txt:
Step 4: Run the tests¶
From the repo root:
6. Summary¶
- Tests live in
test/inside each package. -
Use GTest via
ament_cmake_gtestand follow the patterns shown in: -
adore_math/test/CMakeLists.txt adore_math_conversions/CMakeLists.txt-
Run tests using:
-
just test_ws– all unit tests in the workspace. colcon test --packages-select <pkg>– a specific package.just test_system– system-level tests.just ci– approximate CI: tests + docs, in a container.- Write tests that are small, deterministic, and focused on invariants and round-trips, mirroring the approach in
adore_mathandadore_math_conversions.