Catkin can run C++ unit tests using
the googletest
library in C++ and
the nosetest
utility in
Python. This page includes instructions for running tests, writing C++ unit
tests and writing Python unit tests.
Catkin can run all tests in the workspace by running the commands:
$ catkin build --make-args tests
$ catkin build --make-args test
The first command (the tests
target) builds the tests and the second command
runs them. You can safely omit the first command if you are only running unit
tests on Python packages, which do not need to be built.
Additionally, you can restrict testing to a list of Catkin packages:
$ catkin build --make-args tests -- my_package1 my_package2
$ catkin build --make-args test -- my_package1 my_package2
This command produces no output. You can use the catkin_test_results
tool to view the test results:
$ catkin_test_results build
Summary: 32 tests, 0 errors, 0 failures
It's often useful to manually run tests, completely bypassing Catkin, during
development. This lets you to see which tests failed, view their console output,
and run specific test suites. This is always possible because Catkin simply
invokes googletest
and nosetest
.
Every catkin_add_gtest
CMake command builds an executable. You can manually
run a test by invoking that executable. For example, if you have the entry
catkin_add_gtest(my_test test/my_test.cpp)
in the my_package
package, you
can run:
$ rosrun my_package my_test
googletest
supports a number of command line options for controlling which
test to run, how many times to run them, and how to format the test results. You
can see the full list of options by passing the --help
flag. One of the most
useful options is to filter which tests to run. First, view a list of tests by
passing the --gtest_list_tests
flag.
$ rosrun my_package my_test --gtest_list_tests
MyFixture.
test1
test2
OtherFixture
test3
You can pass any of those names to --gtest_filter
option to explicitly enable
(or disable) a particular test:
$ rosrun my_package my_test --gtest_filter=MyFixture.test1 # only test1
$ rosrun my_package my_test --gtest_filter=-MyFixture.test1 # everything but test1
$ rosrun my_package my_test --gtest_filter=MyFixture.* # only tests in MyFixture
You can use the nosetests
command to directly run your Python unit tests:
$ nosetests -v prpy/tests/planning # run tests in a directory
$ nosetests -v prpy/tests/planning/test_CBiRRT.py # run tests in a file
The -v
flag tells nosetests
to print the name of each test before it runs
it. You can run a specific test by passing appending its name to the end of the
path using the syntax path/to/test.py:MyTestSuite.test_MyTestName
. You may
also want to pass the -s
flag, which tells nosetests
to print the output of
the test immediately. For example, you could run:
$ nosetests -s prpy/tests/planning/test_CBiRRT.py:CBiRRTPlannerTest.test_PlanToConfiguration_GoalInCollision_Throws
You can view the full list of tests, without running them, by running
$ nosetests -v --collect-only prpy/tests/planning
You should specify any dependencies that are required for unit tests
using
<test_depend>
tags in
your package's package.xml
file. At a minimum, C++ packages typically depend
on gtest
and Python packages typically depend on python-nose
. All
<build_depend>
and <exec_depend>
are
implicitly considered test dependencies and, thus, should not be duplicated.
You should use the Google Test framework to write C++ unit
tests. The primer and samples pages in the
Google Test documentation do a good job explaining the
basics. The advanced guide
and reference sheet outline the full set of EXPECT
and
ASSERT
macros available for use.
Once you written your tests, you can register them with Catkin using
the catkin_add_gtest
macro:
if(CATKIN_ENABLE_TESTING)
catkin_add_gtest(test_MyClass1 tests/test_MyClass1.cpp)
catkin_add_gtest(test_MyClass2 tests/test_MyClass2.cpp)
endif(CATKIN_ENABLE_TESTING)
This command defines a new target. Remember that you must set
target_link_libraries
and other target-specific attributes that are necessary
to build the test. In general, you can treat catkin_add_gtest
like any other
add_executable
command in your CMakeLists.txt
file.
nosetests
changes PYTHONPATH
and may cause relative imports
to fail. You can work around this by modifying sys.path
at the very top of
your scripts:
import os.path, sys
sys.path = [os.path.abspath(os.path.dirname(__file__))] + sys.path
You should use the unittest
module, which is part of the standard
library, to write unit tests in Python. Tests are typically stored in the
tests/
directory, are prefixed by test_
and
do not have the executable bit set.
Each file or directory of tests must be registered with Catkin in the
CMakeLists.txt
file using the catkin_add_nosetests
function
if the CATKIN_ENABLE_TESTING
variable is set. It's personal preference whether
to put all tests in one file or split them among multiple files; use your best
judgement.
Suppose we are writing tests for the my_package
package and they are split
between tests/test_MyClass1.py
and tests/test_MyClass2.py
. The
CMakeLists.txt
file should include the block:
if(CATKIN_ENABLE_TESTING)
catkin_add_nosetests(tests/test_MyClass1.py)
catkin_add_nosetests(tests/test_MyClass2.py)
endif(CATKIN_ENABLE_TESTING)
Alternatively, you can register the entire tests
directory with nosetests
:
if(CATKIN_ENABLE_TESTING)
catkin_add_nosetests(tests)
endif(CATKIN_ENABLE_TESTING)