Skip to main content

ROS2 easy-test

PyPI version license ros2 version Python version

CI status documentation status code style linter static type checker

A Python test framework for ROS2 allowing for:

  • simple and expressive assertions based on message and service interactions (black box testing)
  • easy integration of existing nodes and launch files
  • testing of nodes implemented in any programming language (C++, Python, ...)
  • works with and without tools like colcon test and pytest
  • is minimalistic and has very few dependencies
  • is typed and documented
  • is tested, used in practice, and maintained

Installation

Just run:

pip install ros2-easy-test

Examples

The following two examples show off the usage of the Python decorators @with_single_node and @with_launch_file, which provide the core functionality of this package. To get a better grasp of their inner workings, have a look at their implementation here. Besides the simple examples here, you can embed everything in unittest.TestCase as well. To check out how, have a look at the provided tests/ for some advanced examples.

Testing a Node

Simple settings where a single node shall be tested can make use of the decorator @with_single_node as in the following example.

from ros2_easy_test import ROS2TestEnvironment, with_launch_file, with_single_node
from my_nodes import Talker
from std_msgs.msg import String

@with_single_node(Talker, watch_topics={"/chatter": String})
def test_simple_publisher(env: ROS2TestEnvironment) -> None:
    response: String = env.assert_message_published("/chatter", timeout=5)
    assert response.data == "Hello World: 0"

You can optionally provide more parameters to the test setting, i.e., additionally pass parameters={"some.thing": 30.2} to the decorator. The argument of the test function receiving the ROS2TestEnvironment must be named env.

Testing a Launch File

For more complex scenarios involving multiple nodes using a launch file (both nodes and launch file being implemented in any language supported by ROS2), the @with_launch_file decorator can be used.

@with_launch_file(
    "example_launch_file.yaml",
    watch_topics={"/some/interesting/response": ColorRGBA},
)
def test_simple_update_launch_file(env: ROS2TestEnvironment) -> None:
    env.publish("/topic/for/node_input", ColorRGBA(r=0.5, g=0.2, b=0.9, a=1.0))
    response_color = env.assert_message_published("/some/interesting/response")
    assert response_color.r == 0.5

You can also pass the literal launch file contents as a str instead of a path like "example_launch_file.yaml". The argument of the test function receiving the ROS2TestEnvironment must be named env.

Note that, however, this method is much slower than the one above. One reason for this is the requirement of a fixed warm-up time for the nodes to be started. This is because the test environment has to wait for the nodes to be ready before it can start listening for messages.

Usage

How you can interact with the node(s)

Using ROS2TestEnvironment, you can call:

  • publish(topic: str, message: RosMessage) -> None
  • listen_for_messages(topic: str, time_span: float) -> List[RosMessage]
  • clear_messages(topic: str) -> None to forget all messages that have been received so far.
  • call_service(name: str, request: Request, timeout_availability: Optional[float], timeout_call: Optional[float]) -> Response

Note that ROS2TestEnvironment is a rclpy.node.Node and thus has all the methods of a ROS2 node. In addition, nothing stops you from using any other means of interacting with ROS2 that would work otherwise.

Using ROS2TestEnvironment, you can assert:

  • assert_message_published(topic: str, timeout: Optional[float]) -> RosMessage
  • assert_no_message_published(topic: str, timeout: Optional[float]) -> None
  • assert_messages_published(topic: str, number: int, ...) -> List[RosMessage]

Generally, you can always test that no exceptions are thrown, e.g., when nodes are initialized (see limitations below).

Combining with other tools

Some hints:

  • If you want to use pytest markers like @pytest.mark.skipif(...), add that above (=before) the @with_single_node(...)/@with_launch_file(...) decorator and it will work just fine.
  • Similarly, you can seamlessly use other tools which annotate test functions, like hypothesis or pytest fixtures. Generally, you have to be mindful of the order of the decorators here. The ROS2TestEnvironment is always added as a keyword argument called env to the test function. See tests/demo/ for a few examples.

Limitations, Design, and Other Projects

See the documentation on that.

Contributing

You can install the development dependencies with pip install -e ".[dev]". After this, you will have access to the configured formatters black . and ruff check ..

You can run the test with simply pytest. Coverage reports and timings will be printed on the command line, and a fresh line-by-line coverage report is in htmlcov/index.html.

Building the documentation is simple too:

# Install the required dependencies
pip install -e ".[doc]"

# Build the documentation
cd doc
make html
# open build/html/index.html in you browser

# You can also run a small webserver to serve the static files with
cd build/html
python -m http.server

Changelog

See Releases.

License

See LICENSE.

Initially developed by Felix Divo at Sailing Team Darmstadt e. V., a student group devoted to robotic sailing based in Darmstadt, Germany. Thanks to Simon Kohaut for his kind and nuanced feedback.

Metadata

Release files for ros2-easy-test 0.2.0.post1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ros2-easy-test 0.2.0.post1
File Size Uploaded Provenance Actions
ros2_easy_test-0.2.0.post1.tar.gz 33.5 kB Without provenance Details for ros2_easy_test-0.2.0.post1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ros2-easy-test 0.2.0.post1
File Interpreter ABI Platform Actions
ros2_easy_test-0.2.0.post1-py3-none-any.whl Python 3 none any Details for ros2_easy_test-0.2.0.post1-py3-none-any.whl

Total release size: 50.0 kB

Release files / ros2_easy_test-0.2.0.post1.tar.gz

Download URL ros2_easy_test-0.2.0.post1.tar.gz
Size 33.5 kB
Tags Source
SHA-256 checksum
How to use checksums
45e9fc802430a6ee2a8084a7e48c961d633088a427593db7b6b204a041204a6a
BLAKE2b-256 checksum
How to use checksums
0c94b0c9659d5d6e9f10727aca4e003465dec52171080ffbd42a8e67ea35c0ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.1 CPython/3.11.3

Release files / ros2_easy_test-0.2.0.post1-py3-none-any.whl

Download URL ros2_easy_test-0.2.0.post1-py3-none-any.whl
Size 16.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5aa46d776c6f2e599a51d35f20fd7ad55b68fba2c1ca42142295148b6a039b66
BLAKE2b-256 checksum
How to use checksums
14450b07a4aab78220b9e5c213e4cc7378fc46557d7dc7321822bb78dc59fbd4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.1 CPython/3.11.3

Security for ros2-easy-test 0.2.0.post1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0.post1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page