背景
rosパッケージを作成する際に、品質担保のために通常単体テストを行う。
googleテストの使用方法やCMakeListsの書き方を備忘録として記載する。
記事の目的
google testでrosパッケージの単体テストを行う
google test
google testでrosパッケージの単体テストを行う方法について記載する。
google testとは
google testは、google社が提供するオープンソースのテストフレームワークである。特徴
- マクロを使用してテストケースを容易に記述できる
- rosの標準のテストフレームワークである
テンプレートのパッケージ構成
google testでrosパッケージの単体テストを行うrosパッケージの構成を記載する。$ tree
.
├── CMakeLists.txt -> /opt/ros/kinetic/share/catkin/cmake/toplevel.cmake
└── sample_pkg # google testでテストを行うサンプルパッケージ
├── CMakeLists.txt # CMakeListsファイル
├── include
│ └── sample_pkg
│ └── sample.hpp # headerファイル
├── launch
│ └── sample.launch #(オプション)launchファイル
├── package.xml # Packageファイル
├── src
│ ├── main.cpp # ソースファイル(main関数のみ)
│ └── sample.cpp # ソースファイル(その他関数, クラス)
└── test
└── utest.cpp # 単体テストファイル
テンプレートのheaderファイルとソースファイル
テンプレートのheaderファイルとソースファイルを記載する。// sample.hpp
#include <ros/ros.h>
namespace sample
{
int func1(int a, int b);
bool func2(int c, int d);
class class3
{
public:
class3();
~class3();
void func4(int e);
void func5(int &f);
protected:
int internal_variable_ = 0;
};
};
// sample.cpp
#include <sample_pkg/sample.hpp>
int sample::func1(int a, int b)
{
return a+b;
}
bool sample::func2(int a, int b)
{
if (a == b)
{
return true;
}
return false;
}
sample::class3::class3()
{}
sample::class3::~class3()
{}
void sample::class3::func4(int e)
{
internal_variable_ = e;
}
void sample::class3::func5(int &f)
{
f = internal_variable_;
}
// main.cpp
#include <sample_pkg/sample.hpp>
int main(int argc, char **argv){
int A = sample::func1(1,3);
return A;
}
テンプレートの単体テストファイル
テンプレートの単体テストファイルを記載する。// utest.cpp
#include <sample_pkg/sample.hpp>
#include <gtest/gtest.h>
// sample::func1のテスト
TEST(Factorial1Test, func1Test)
{
int A = sample::func1(1,2);
EXPECT_EQ(3, A); // A == 3 かチェック
}
// sample::func2のテスト
TEST(Factorial2Test, func2Test)
{
EXPECT_TRUE(sample::func2(1,1)); // a == bの時、戻り値がtrueかチェック
EXPECT_FALSE(sample::func2(1,2)); // a != bの時、戻り値がfalseかチェック
}
// sample::class3のテスト
TEST(Class3Test, func4_5Test1)
{
sample::class3 c;
int a;
c.func5(a);
EXPECT_EQ(0, a); // 初期状態でc.func5(a)のa==0かチェック
}
// sample::class3のテスト
TEST(Class3Test, func4_5Test2)
{
sample::class3 c;
int a = 4;
int b = 0;
c.func4(a);
c.func5(b);
EXPECT_EQ(a, b); // c.func4(a)を行った後、c.func5(b)のb==aかチェック
}
// Run all the tests that were declared with TEST()
int main(int argc, char **argv){
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
テンプレートのCMakeListsファイルとPackageファイル
テンプレートのCMakeListsファイルとPackageファイルを記載する。# CMakeLists.txt
cmake_minimum_required(VERSION 2.8.3)
project(sample_pkg)
## Compile as C++11, supported in ROS Kinetic and newer
add_compile_options(-std=c++11 -Wall -g -O3)
## Find catkin macros and libraries
find_package(catkin REQUIRED COMPONENTS
roscpp
)
###################################
## catkin specific configuration ##
###################################
## Declare things to be passed to dependent projects
catkin_package(
INCLUDE_DIRS include
LIBRARIES sample_pkg
)
###########
## Build ##
###########
## Specify additional locations of header files
include_directories(include
/usr/local/include
${catkin_INCLUDE_DIRS}
)
## Declare a C++ library
add_library(${PROJECT_NAME}_lib
src/sample.cpp
)
## Declare a C++ executable
add_executable(${PROJECT_NAME}
src/main.cpp
)
## Specify libraries to link a library or executable target against
target_link_libraries(${PROJECT_NAME}_lib
${catkin_LIBRARIES}
)
target_link_libraries(${PROJECT_NAME}
${PROJECT_NAME}_lib
${catkin_LIBRARIES}
)
#############
## Install ##
#############
## Mark executables and/or libraries for installation
install(TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
## Mark cpp header files for installation
install(DIRECTORY include/${PROJECT_NAME}/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.hpp"
)
#############
## Testing ##
#############
## Add gtest based cpp test target and link libraries
catkin_add_gtest(${PROJECT_NAME}_test test/utest.cpp)
target_link_libraries(${PROJECT_NAME}_test
${PROJECT_NAME}_lib
${catkin_LIBRARIES}
)
<!-- package.xml -->
<?xml version="1.0"?>
<package format="2">
<name>sample_pkg</name>
<version>0.0.0</version>
<description>The sample package</description>
<!-- One maintainer tag required, multiple allowed, one person per tag -->
<maintainer email="xxx@yyy.zz">EmptySet</maintainer>
<!-- One license tag required, multiple allowed, one license per tag -->
<!-- Commonly used license strings: -->
<!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
<license>MIT</license>
<!-- Url tags are optional, but multiple are allowed, one per tag -->
<!-- Optional attribute type can be: website, bugtracker, or repository -->
<url type="website">https://ittechnicalmemos.blogspot.com</url>
<!-- Author tags are optional, multiple are allowed, one per tag -->
<!-- Authors do not have to be maintainers, but could be -->
<author email="xxx@yyy.zz">EmptySet</author>
<!-- The *depend tags are used to specify dependencies -->
<!-- Dependencies can be catkin packages or system dependencies -->
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_export_depend>roscpp</build_export_depend>
<exec_depend>roscpp</exec_depend>
</package>
テンプレートの単体テスト実行方法
テンプレートの単体テスト実行方法及び結果を記載する。$ catkin_make run_tests
...
- run_tests.py: execute commands
/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
[==========] Running 4 tests from 3 test cases.
[----------] Global test environment set-up.
[----------] 1 test from Factorial1Test
[ RUN ] Factorial1Test.func1Test
[ OK ] Factorial1Test.func1Test (0 ms)
[----------] 1 test from Factorial1Test (0 ms total)
[----------] 1 test from Factorial2Test
[ RUN ] Factorial2Test.func2Test
[ OK ] Factorial2Test.func2Test (0 ms)
[----------] 1 test from Factorial2Test (0 ms total)
[----------] 2 tests from Class3Test
[ RUN ] Class3Test.func4_5Test1
[ OK ] Class3Test.func4_5Test1 (0 ms)
[ RUN ] Class3Test.func4_5Test2
[ OK ] Class3Test.func4_5Test2 (0 ms)
[----------] 2 tests from Class3Test (0 ms total)
[----------] Global test environment tear-down
[==========] 4 tests from 3 test cases ran. (0 ms total)
[ PASSED ] 4 tests.
-- run_tests.py: verify result "/home/emptySet/work_space/build/test_results/sample_pkg/gtest-sample_pkg_test.xml"
...
テスト結果がNGの場合は、下記のように表示される。
$ catkin_make run_tests
...
/home/emptySet/work_space/src/sample_pkg/test/utest.cpp:31: Failure
Value of: a
Actual: 4
Expected: 2
[ FAILED ] Class3Test.func4_5Test2 (0 ms)
...
[ FAILED ] 1 test, listed below:
[ FAILED ] Class3Test.func4_5Test2
1 FAILED TEST
...
備考
- google testのマクロはここを参照。
まとめ
- google testでrosパッケージの単体テストを行う方法を調査、記載した
参考文献
変更履歴
- 2019/09/12: 新規作成
0 件のコメント:
コメントを投稿