Skip to content

Commit

Permalink
Some testing basics (#3084)
Browse files Browse the repository at this point in the history
* Some testing basics

Signed-off-by: David V. Lu <davidvlu@gmail.com>
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
  • Loading branch information
DLu authored Oct 14, 2022
1 parent 8771452 commit 8910a80
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 1 deletion.
2 changes: 1 addition & 1 deletion source/The-ROS2-Project/Contributing/Developer-Guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ Examples:
Testing
^^^^^^^

All packages should have some level of system, integration, and/or unit tests.
All packages should have some level of :ref:`system, integration, and/or unit tests.<TestingMain>`

**Unit tests** should always be in the package which is being tested and should make use of tools like ``Mock`` to try and test narrow parts of the code base in constructed scenarios.
Unit tests should not bring in test dependencies that are not testing tools, e.g. gtest, nosetest, pytest, mock, etc...
Expand Down
1 change: 1 addition & 0 deletions source/Tutorials/Intermediate.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ Intermediate
Intermediate/Monitoring-For-Parameter-Changes-CPP
Intermediate/Launch/Launch-Main
Intermediate/Tf2/Tf2-Main
Intermediate/Testing/Testing-Main
Intermediate/URDF/URDF-Main
24 changes: 24 additions & 0 deletions source/Tutorials/Intermediate/Testing/CLI.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.. TestingCLI:
Running Tests in ROS 2 from the Command Line
============================================

Build and run your tests
^^^^^^^^^^^^^^^^^^^^^^^^

To compile and run the tests, simply run the `test <https://colcon.readthedocs.io/en/released/reference/verb/test.html>`__ verb from ``colcon``.

.. code-block:: console
colcon test --cmake-args tests [package_selection_args]
(where ``package_selection_args`` are optional package selection arguments for ``colcon`` to limit which packages are built and run)

Examine Test Results
^^^^^^^^^^^^^^^^^^^^

To see the results, simply run the `test-result <https://colcon.readthedocs.io/en/released/reference/verb/test-result.html>`__ verb from ``colcon``.

.. code-block:: console
colcon test-result --all
65 changes: 65 additions & 0 deletions source/Tutorials/Intermediate/Testing/Python.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
.. TestingPython:
Writing Basic Tests with Python
===============================

Starting point: we'll assume you have a :ref:`basic ament_python package<CreatePkg>` set up already and you want to add some tests to it.

Package Setup
-------------

setup.py
^^^^^^^^

Your ``setup.py`` must a test dependency on ``pytest`` within the call to ``setup(...)``:

.. code-block:: python
tests_require=['pytest'],
Test Files and Folders
^^^^^^^^^^^^^^^^^^^^^^

Your test code needs to go in a folder named ``tests`` in the root of your package.

Any file that contains tests that you want to run must have the pattern ``test_FOO.py`` where ``FOO`` can be replaced with anything.

Example package layout:
"""""""""""""""""""""""

.. code-block::
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
Test Contents
-------------

You can now write tests to your heart's content. There are `plenty of resources on pytest <https://docs.pytest.org>`__, but in short, you can write functions with the ``test_`` prefix and include whatever assert statements you'd like.


.. code-block:: python
def test_math():
assert 2 + 2 == 5 # This should fail for most mathematical systems
Special Commands
----------------

Beyond the :doc:`standard colcon testing commands <CLI>` you can also specify arguments to the ``pytest`` framework from the command line with the ``--pytest-args`` flag.
For example, you can specify the name of the function to run with


.. code-block:: console
colcon test --packages-select <name-of-pkg> --pytest-args -k name_of_the_test_function
42 changes: 42 additions & 0 deletions source/Tutorials/Intermediate/Testing/Testing-Main.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.. _TestingMain:

Testing
=======

Why automatic tests?
--------------------

Here are some of the many good reasons why should we have automated tests:

* You can make incremental updates to your code more quickly. ROS has hundreds of packages with many interdependencies, so it can be hard to anticipate the problems a small change might cause. If your change passes the unit tests, you can be more confident that you haven't introduced problems — or at least the problems aren't your fault.
* You can refactor your code with greater confidence. Passing the unit tests verifies that you haven't introduced any bugs while refactoring. This gives you this wonderful freedom from change fear!
* It leads to better designed code. Unit tests force you to write your code so that it can be more easily tested. This often means keeping your underlying functions and framework separate, which is one of our design goals with ROS code.
* They prevent recurring bugs (bug regressions). It's a good practice to write a unit test for every bug you fix. In fact, write the unit test before you fix the bug. This will help you to precisely, or even deterministically, reproduce the bug, and much more precisely understand what the problem is. As a result, you will also create a better patch, which you can then test with your regression test to verify that the bug is fixed. That way the bug won't accidentally get reintroduced if the code gets modified later on. It also means that it will be easier to convince the reviewer of the patch that the problem is solved, and the contribution is of high quality.
* Other people can work on your code more easily (an automatic form of documentation). It can be hard to figure out whether or not you've broken someone else's code when you make a change. The unit tests are a tool for other developers to validate their changes. Automatic tests document your coding decisions, and communicate to other developers automatically about their violation. Thus tests become documentation for your code — a documentation that does not need to be read for the most time, and when it does need to be inspected the test system will precisely indicate what to read (which tests fail). By writing automatic tests you make other contributors faster. This improves the entire ROS project.
* It is much easier to become a contributor to ROS if we have automated unit tests. It is very difficult for new external developers to contribute to your components. When they make changes to code, they are often doing it in the blind, driven by a lot of guesswork. By providing a harness of automated tests, you help them in the task. They get immediate feedback for their changes. It becomes easier to contribute to a project, and new contributors to join more easily. Also their first contributions are of higher quality, which decreases the workload on maintainers. A win-win!
* Automatic tests simplify maintainership. Especially for mature packages, which change more slowly, and mostly need to be updated to new dependencies, an automatic test suite helps to very quickly establish whether the package still works. This makes it much easier to decide whether the package is still supported or not.
* Automatic tests amplify the value of Continuous Integration. Regression tests, along with normal scenario-based requirements tests, contribute to overall body of automated tests for your component. Your component is better tested against evolution of other APIs that it depends on (CI servers will tell you better and more precisely what problems develop in your code).

Perhaps the most important benefit of writing tests is that tests make you a good citizen.
Tests influence quality in the long term.
It is a well accepted practice in many open-source projects.
By writing regressions tests, you are contributing to long term quality of the ROS ecosystem.

Is this all coming for free?
----------------------------

Of course, there is never free lunch.
To get the benefits of testing, some investment is necessary.

* You need to develop a test, which sometimes may be difficult or costly. Sometimes it might also be nontrivial, as the test should be automatic. Things get particularly hairy if your tests should involve special hardware (they should not: try to use simulation, mock the hardware, or narrow down the test to a smaller software problem) or require external environment, for instance human operators.
* Regression tests and other automatic tests need to be maintained. When the design of the component changes, a lot of tests become invalidated (for instance they no longer compile, or throw runtime exceptions related to the API design). These tests fail not only because the redesign re-introduced bugs but also because they need to be updated to the new design. Occasionally, with bigger redesigns, old regression tests should be dropped.
* Large bodies of tests can take a long time to run, which can increase Continuous Integration server costs.

Available Tutorials:
--------------------

.. toctree::
:maxdepth: 1

CLI
Python

0 comments on commit 8910a80

Please sign in to comment.