2019/09/12

google testでrosパッケージの単体テストを行う方法

背景


rosパッケージを作成する際に、品質担保のために通常単体テストを行う。
googleテストの使用方法やCMakeListsの書き方を備忘録として記載する。

記事の目的


google testでrosパッケージの単体テストを行う

google test


google testでrosパッケージの単体テストを行う方法について記載する。

google testとは

google testは、google社が提供するオープンソースのテストフレームワークである。

特徴

  • マクロを使用してテストケースを容易に記述できる
  • rosの標準のテストフレームワークである

テンプレートのパッケージ構成

google testでrosパッケージの単体テストを行うrosパッケージの構成を記載する。
  1. $ tree
  2. .
  3. ├── CMakeLists.txt -> /opt/ros/kinetic/share/catkin/cmake/toplevel.cmake
  4. └── sample_pkg # google testでテストを行うサンプルパッケージ
  5. ├── CMakeLists.txt # CMakeListsファイル
  6. ├── include
  7. └── sample_pkg
  8. └── sample.hpp # headerファイル
  9. ├── launch
  10. └── sample.launch #(オプション)launchファイル
  11. ├── package.xml # Packageファイル
  12. ├── src
  13. ├── main.cpp # ソースファイル(main関数のみ)
  14. └── sample.cpp # ソースファイル(その他関数, クラス)
  15. └── test
  16. └── utest.cpp # 単体テストファイル

テンプレートのheaderファイルとソースファイル

テンプレートのheaderファイルとソースファイルを記載する。
  1. // sample.hpp
  2. #include <ros/ros.h>
  3. namespace sample
  4. {
  5. int func1(int a, int b);
  6. bool func2(int c, int d);
  7. class class3
  8. {
  9. public:
  10. class3();
  11. ~class3();
  12. void func4(int e);
  13. void func5(int &f);
  14. protected:
  15. int internal_variable_ = 0;
  16. };
  17. };

  1. // sample.cpp
  2. #include <sample_pkg/sample.hpp>
  3. int sample::func1(int a, int b)
  4. {
  5. return a+b;
  6. }
  7. bool sample::func2(int a, int b)
  8. {
  9. if (a == b)
  10. {
  11. return true;
  12. }
  13. return false;
  14. }
  15. sample::class3::class3()
  16. {}
  17. sample::class3::~class3()
  18. {}
  19. void sample::class3::func4(int e)
  20. {
  21. internal_variable_ = e;
  22. }
  23. void sample::class3::func5(int &f)
  24. {
  25. f = internal_variable_;
  26. }

  1. // main.cpp
  2. #include <sample_pkg/sample.hpp>
  3. int main(int argc, char **argv){
  4. int A = sample::func1(1,3);
  5. return A;
  6. }


テンプレートの単体テストファイル

テンプレートの単体テストファイルを記載する。
  1. // utest.cpp
  2. #include <sample_pkg/sample.hpp>
  3. #include <gtest/gtest.h>
  4. // sample::func1のテスト
  5. TEST(Factorial1Test, func1Test)
  6. {
  7. int A = sample::func1(1,2);
  8. EXPECT_EQ(3, A); // A == 3 かチェック
  9. }
  10. // sample::func2のテスト
  11. TEST(Factorial2Test, func2Test)
  12. {
  13. EXPECT_TRUE(sample::func2(1,1)); // a == bの時、戻り値がtrueかチェック
  14. EXPECT_FALSE(sample::func2(1,2)); // a != bの時、戻り値がfalseかチェック
  15. }
  16. // sample::class3のテスト
  17. TEST(Class3Test, func4_5Test1)
  18. {
  19. sample::class3 c;
  20. int a;
  21. c.func5(a);
  22. EXPECT_EQ(0, a); // 初期状態でc.func5(a)のa==0かチェック
  23. }
  24. // sample::class3のテスト
  25. TEST(Class3Test, func4_5Test2)
  26. {
  27. sample::class3 c;
  28. int a = 4;
  29. int b = 0;
  30. c.func4(a);
  31. c.func5(b);
  32. EXPECT_EQ(a, b); // c.func4(a)を行った後、c.func5(b)のb==aかチェック
  33. }
  34. // Run all the tests that were declared with TEST()
  35. int main(int argc, char **argv){
  36. testing::InitGoogleTest(&argc, argv);
  37. return RUN_ALL_TESTS();
  38. }

テンプレートのCMakeListsファイルとPackageファイル

テンプレートのCMakeListsファイルとPackageファイルを記載する。
  1. # CMakeLists.txt
  2. cmake_minimum_required(VERSION 2.8.3)
  3. project(sample_pkg)
  4. ## Compile as C++11, supported in ROS Kinetic and newer
  5. add_compile_options(-std=c++11 -Wall -g -O3)
  6. ## Find catkin macros and libraries
  7. find_package(catkin REQUIRED COMPONENTS
  8.              roscpp
  9. )
  10. ###################################
  11. ## catkin specific configuration ##
  12. ###################################
  13. ## Declare things to be passed to dependent projects
  14. catkin_package(
  15.    INCLUDE_DIRS include
  16.    LIBRARIES sample_pkg
  17. )
  18. ###########
  19. ## Build ##
  20. ###########
  21. ## Specify additional locations of header files
  22. include_directories(include
  23.                     /usr/local/include
  24.                     ${catkin_INCLUDE_DIRS}
  25. )
  26. ## Declare a C++ library
  27. add_library(${PROJECT_NAME}_lib
  28.             src/sample.cpp
  29. )
  30. ## Declare a C++ executable
  31. add_executable(${PROJECT_NAME}
  32.                src/main.cpp
  33. )
  34. ## Specify libraries to link a library or executable target against
  35. target_link_libraries(${PROJECT_NAME}_lib
  36.                       ${catkin_LIBRARIES}
  37. )
  38. target_link_libraries(${PROJECT_NAME}
  39.       ${PROJECT_NAME}_lib
  40.                       ${catkin_LIBRARIES}
  41. )
  42. #############
  43. ## Install ##
  44. #############
  45. ## Mark executables and/or libraries for installation
  46. install(TARGETS ${PROJECT_NAME}
  47.         ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
  48.         LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
  49.         RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
  50. )
  51. ## Mark cpp header files for installation
  52. install(DIRECTORY include/${PROJECT_NAME}/
  53.         DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
  54.         FILES_MATCHING PATTERN "*.hpp"
  55. )
  56. #############
  57. ## Testing ##
  58. #############
  59. ## Add gtest based cpp test target and link libraries
  60. catkin_add_gtest(${PROJECT_NAME}_test test/utest.cpp)
  61. target_link_libraries(${PROJECT_NAME}_test
  62.                       ${PROJECT_NAME}_lib
  63.                       ${catkin_LIBRARIES}
  64. )

  1. <!-- package.xml -->
  2. <?xml version="1.0"?>
  3. <package format="2">
  4. <name>sample_pkg</name>
  5. <version>0.0.0</version>
  6. <description>The sample package</description>
  7. <!-- One maintainer tag required, multiple allowed, one person per tag -->
  8. <maintainer email="xxx@yyy.zz">EmptySet</maintainer>
  9. <!-- One license tag required, multiple allowed, one license per tag -->
  10. <!-- Commonly used license strings: -->
  11. <!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
  12. <license>MIT</license>
  13. <!-- Url tags are optional, but multiple are allowed, one per tag -->
  14. <!-- Optional attribute type can be: website, bugtracker, or repository -->
  15. <url type="website">https://ittechnicalmemos.blogspot.com</url>
  16. <!-- Author tags are optional, multiple are allowed, one per tag -->
  17. <!-- Authors do not have to be maintainers, but could be -->
  18. <author email="xxx@yyy.zz">EmptySet</author>
  19. <!-- The *depend tags are used to specify dependencies -->
  20. <!-- Dependencies can be catkin packages or system dependencies -->
  21. <buildtool_depend>catkin</buildtool_depend>
  22. <build_depend>roscpp</build_depend>
  23. <build_export_depend>roscpp</build_export_depend>
  24. <exec_depend>roscpp</exec_depend>
  25. </package>

テンプレートの単体テスト実行方法

テンプレートの単体テスト実行方法及び結果を記載する。
  1. $ catkin_make run_tests
  2. ...
  3. - run_tests.py: execute commands
  4. /home/emptySet/work_space/devel/lib/sample_pkg/sample_pkg_test --gtest_output=xml:/home/emptySet/work_space/build/test_results/sample_pkg/gtest-sample_pkg_test.xml
  5. [==========] Running 4 tests from 3 test cases.
  6. [----------] Global test environment set-up.
  7. [----------] 1 test from Factorial1Test
  8. [ RUN ] Factorial1Test.func1Test
  9. [ OK ] Factorial1Test.func1Test (0 ms)
  10. [----------] 1 test from Factorial1Test (0 ms total)
  11. [----------] 1 test from Factorial2Test
  12. [ RUN ] Factorial2Test.func2Test
  13. [ OK ] Factorial2Test.func2Test (0 ms)
  14. [----------] 1 test from Factorial2Test (0 ms total)
  15. [----------] 2 tests from Class3Test
  16. [ RUN ] Class3Test.func4_5Test1
  17. [ OK ] Class3Test.func4_5Test1 (0 ms)
  18. [ RUN ] Class3Test.func4_5Test2
  19. [ OK ] Class3Test.func4_5Test2 (0 ms)
  20. [----------] 2 tests from Class3Test (0 ms total)
  21. [----------] Global test environment tear-down
  22. [==========] 4 tests from 3 test cases ran. (0 ms total)
  23. [ PASSED ] 4 tests.
  24. -- run_tests.py: verify result "/home/emptySet/work_space/build/test_results/sample_pkg/gtest-sample_pkg_test.xml"
  25. ...

テスト結果がNGの場合は、下記のように表示される。
  1. $ catkin_make run_tests
  2. ...
  3. /home/emptySet/work_space/src/sample_pkg/test/utest.cpp:31: Failure
  4. Value of: a
  5. Actual: 4
  6. Expected: 2
  7. [ FAILED ] Class3Test.func4_5Test2 (0 ms)
  8. ...
  9. [ FAILED ] 1 test, listed below:
  10. [ FAILED ] Class3Test.func4_5Test2
  11. 1 FAILED TEST
  12. ...

備考

  • google testのマクロはここを参照。

まとめ


  • google testでrosパッケージの単体テストを行う方法を調査、記載した

参考文献



変更履歴


  1. 2019/09/12: 新規作成

0 件のコメント:

コメントを投稿

MQTTの導入

背景 IoTデバイスの接続環境構築のため、MQTT(mosquitto)の導入を行った。 記事の目的 MQTT(mosquitto)をUbuntuに導入する mosquitto ここではmosquittoについて記載する。 MQTT MQTT(Message Qu...