A Gentle Introduction to Gtest
Víctor González [email protected]
March 2014
Test Driven Development in ROS
OutlineWhat to expectMotivationTesting LevelsWriting your first testsAdvice on making good testsResourcesExercise
Start with an example
Download material at:https://github.com/VGonPa/ros-testing-seminar
git clone https://github.com/VGonPa/ros-testing-seminar.git
What to expectfrom this seminar
What to expect
“Will I become a TDD master with this seminar?”
“Actually you might, eventually,if you start writing tests today!”
What to expect
You will learn where to start,the basics, and where to find more
information and help.
Motivation
Motivation
"Tests + Programming" is faster than just "Programming" [1]
MotivationSW Evolves
Requirements changeBug correctionsOptimizationsImprovements on design
How do you know if a change in your code didn’t break your previous work?
MotivationNOT testing is very dangerous:
“(Making large changes without tests) is like doing aerial gymnastics without a net.” [1]
The later you detect a bug, the more expensive is to fix it:
A bug detected in production may be REALLY expensiveLet alone if tomorrow you have a demo!
MotivationSome advantages of writing testsIt forces you to design better code
Faster incremental upgrades
A clear metric of your progress
It lets you refactor with greater confidence
Prevents recurring bugs
It enables you to blame others!
Other people can work with your code more easily
MotivationThe worst disadvantage
It will affect your thinking process......and your programming style.
But you will become a better programmer!
Motivation
“I don’t have time to write tests!”
Had you done the tests before, now you'd have time to do them!
More tests = less time debuggingMore tests = more time to program features
Test Driven Development (TTD)The process
Before programming, write tests
Write only the needed code to make the tests pass
Refactor to eliminate duplicated code, etc.
Repeat
Test Driven Development (TTD)
“Do I really need to write tests first?”
It’s much better to write them first,but if you don’t, be sure that your code is properly tested
Testing Levels
Imagine a simple scenario
N1 N2
Each node has its own code...
N1 N2
This is better...
N1 N2
There you have the first level
N1 N2
Library Unit Testing
Library Unit testing
N1
Library Unit Testing Test only your libraries
Code must be ROS Agnostic
GTest/Unittest(python)
Library Unit testing
N1Test each component separately
Library Unit Testing
N1
Test for:
common cases
extreme cases
Input errors
methods pre and post conditions
Now let’s test the node itself
N1 N2
Node LevelTesting
Node Level Unit testing
N1
Node LevelTesting
Test Node start/shutdown
Test Node external APIservices, published topics, subscribed topics (params?)
RosTest + GTest/Unittest
And, finally, the whole system
N1 N2
Integration/Regression Testing
Integration Testing
N1 N2
Test multiple nodes working as expected
RosTest + GTest/Unittest
Testing Levels: Overview
N1 N2
Library UnitTesting
Node LevelTesting
Integration/Regression Testing
Writing your first testsin ROS
Gtest and rostest
ROS provides two tools for executing tests:
gtest and rostest
GTestGoogle’s tool for unit testing
Regular cpp files
Executed with any of the following: ./my_test_file
make test # needs macro in CMakeLists.txt
rosmake <package_name> -t # needs macro in CMakeLists.txt
http://wiki.ros.org/gtest
Gtest and rostest
GTest
Gtest tutorials are quite good. We won’t cover them here.Read them if you don’t know how to write Gtests.
Gtest and rostest
Gtest and rostestrostest
roslaunch extension to launch tests
.launch syntax with added <test> tag
executed with any of the following: rostest <pgk_name> <test_name>.test
make test # needs macro in CMakeLists.txt
rosmake <package_name> -t # needs macro in CMakeLists.txt
http://wiki.ros.org/rostesthttp://wiki.ros.org/rostest/Writinghttp://wiki.ros.org/roslaunch/XML/test <------ <test> tag reference
Where should I use each one?
N1 N2
Node
Integration/Regression
Library
GtestRostest (+ Gtest)
Package structure with tests
my_ros_pkg/
CMakeLists.txt
bin/
build/
msg/
...
src/
test/ <--- gtests go here
test/ <--- rostests go here
InstallationGTestInstall: bash> sudo apt-get install libgtest-devIn your header files:
#include <gtest/gtest.h>
GMockInstall bash> sudo apt-get install google-mock
In your header files:#include <gmock/gmock.h>
Gtest CMakeLists.txt
# add gtest
rosbuild_add_gtest(test/my_test test/mytest.cpp
[other sources])# link required libraries
target_link_libraries(test/mytest linked_libraries)
rostest CMakeLists.txt
# add the test executable,
# keep it from being built by "make all"
rosbuild_add_executable(test_mynode EXCLUDE_FROM_ALL
src/test/test_mynode.cpp)
# Link test_mynode against gtest
# and add a dependency to the "test" target
rosbuild_add_gtest_build_flags(test_mynode)
# Make sure rostest launches test/mynode.test during "make test"
rosbuild_add_rostest(test/mynode.test)
Let’s see an example
Checkout the package rostest_node_example from the material
Some adviseHow to make good tests
What to testExample: max(list_of_ints)
Normal casesmax([10,3,0,-1,8])
Extreme casesmax([3,3,3,3,3,3])
max(2)
Error casesmax([‘aaa’,3,nan,None])
max([])
What not to testThe test itselfModules that cannot be broken (or that there is no solution):
System callsHardware failures
Modules from which your code depends on:Standard Libraries, modules written by others, etc.
They already have (or should have) their own tests
Exhaustive tests
Writing more “testable” codeSometimes it’s difficult to test a component in isolation
Dependencies between components
Some components might be on the network (eg. sockets)
Some components might needuser input
Some comopnents might just be slow to test
Writing more “testable” code
Solution: Break dependencies
Program against interfaces
Specify dependencies in the constructor
Use mocks in your tests
Common features of good testsA good test should be:
Independent1. You do not need to read other tests to understand what a test does2. If a test fails, it should be easy to find the bug3. Each test focuses on a single aspect
Repetible
Quick: Use mocks
Small: Enables you to easily spot bugs. Big tests functions have many parts affecting each other
Beware the Unit-Integration Chimera!
Unit TestingSweet spot
Integration TestingSweet spot
It will eat your productivity!
Bibliography and Resources
Bibliography and ResourcesB. Eckel, "Thinking in C++ Volume 2". (online version)
Google C++ Testing Framework projectProject: http://code.google.com/p/googletest/
Guía inicial: http://code.google.com/p/googletest/wiki/V1_6_Primer
Avanzado: http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide
Ejemplos: http://code.google.com/p/googletest/wiki/V1_6_Samples
Dependency injection, mocks: Google Mock: http://code.google.com/p/googlemock/
Bibliography and ResourcesROS Unit Testing: http://wiki.ros.org/UnitTesting
ROS GTest: http://wiki.ros.org/gtest
ROS rostest: http://wiki.ros.org/rostest
Bibliography and ResourcesThis seminar has been greatly inspired from this talk from Zhanyong Wan:
Effective C++ Testing Using Google Test
There you will find more information regarding Gtest and Unit testing in general
Questions?https://github.com/VGonPa/ros-testing-seminar
Excercise
1. Counter node’s counter should be initiated by parameter to any number
2. Factorial calculates factorial of counter3. Test the library, node and integration using gtest +
rostests
counter_node factorial_node
/counter /factorial/do_increment
This seminar is licensed under the Creative Commons license CC Attribution 4.0 International
You are free to use and adapt this presentation as long as you give credit to the author.More information can be found here:
http://creativecommons.org/licenses/by/4.0/
Top Related