ETロボコンにおける開発環境 - GoogleTest
はじめに
本記事では、ETロボコンでの開発環境にGoogle Testを導入できるようになることを目指します。Google Test は、Googleが開発したC++のUnitTest用のフレームワークです。
UnitTestを作ることで、自分たちが作ったコードに自信を持つことができるだけではなく、ソースコードの設計も向上します。つまり、わかりやすいコードが増えていく、ということなのです。これは、ETロボコンの開発を進めるうえで大きなアドバンテージになるでしょう。さらに、Google Testを使うことで、デバッグがやりやすい環境を手に入れる、ということにも繋がります。いいことが沢山あるGoogle Testなので、ぜひ、Google Testの導入にチャレンジして欲しいと思います。なお、デバッグに関しては、本記事では触れませんが、別の記事にて記載したいと思います。
想定読者
- ETロボコンに参加する開発者
- C++を用いた開発に携わる者
ETロボコンとは?
そもそも、ETロボコンとは何か?ということですが、ETロボコンは、2002年から開始されたソフトウェア重視のロボットコンテストであり、組込み技術者の育成を目的としています。このコンテストは、その長年にわたる開催と貢献により、経済産業大臣賞を受賞しています。
詳細は、下記を参照してください。
ETロボコンにおける開発環境
前提として、ETロボコンの開発環境の概要は、以下の通りとなります。
- WSL上のUbuntuを使用
- 統合開発環境としてVisual Studio Codeを採用
- プログラミング言語はC++/C
- Unityで動作するシミュレータを利用
- 実機はRaspberry Pi + SPIKE上で動作
これらの環境は、基本的に主催者から提供されます。
概要説明
Google Test とは
Google Testは、Googleによって開発されたC++のためのオープンソーステストフレームワークです。Google TestはxUnitアーキテクチャを基にしています。xUnitアーキテクチャは、ソフトウェアテストのための一連のテストフレームワークであり、各テストケースを個別のテストメソッドとして実装し、それぞれを独立して実行できるように設計されています。これにより、テストの作成、実行、そして結果の分析が容易になります。Google Testを使用することで、C++プログラムの自動化されたユニットテストを簡単に作成、実行、共有することが可能となり、開発プロセスの効率化とコード品質の向上に貢献します。
なぜ、Google Testか?
C++のユニットテストフレームワークは、いくつか存在するようです。もし、現在、所属している組織で使っているフレームワークがあれば、それを使うのが、一番の選択肢になると思います。もし、そういったものがないのであれば、Google Testは、上位候補になります。正直に言うと、複数のフレームワークを徹底比較したわけではありません。ただ、Google というネームバリューで、これを採用してみました。
もし、他のフレームワークと比較したい、という方は、そのような記事があるので、ご確認ください。
例えば、以下のようなものがありました。
Comparison of C++ Unit Test Frameworks
C言語用のユニットテスト・フレームワークおすすめ3選
TDDと相性の良いC、C++のユニットテスティングフレームワークとは
C/C++のユニットテストフレームワーク CppUTest が便利
Google Testを導入するとどんな感じになるか?
Google Testを導入し、TERMINAL上でテストを実行すると、下記のようにテストが実行されます。
ここでは、8個のテストが実行され、すべてのテストをパスしています。
題材
今回は、テストターゲットとして、Stringクラスを扱います。Stringクラスは、C++標準ライブラリのstd::stringクラスを真似たもので、String.hの中に実装も含めて書いてます。cppファイルはありません。
導入手順
ここからは、Visual Studio Code上でGoogle Testを導入する手順を説明します。Google Testの公式ページには、BazelとCMakeを使ったビルドの方法が記載されていますが、本記事では、CMakeを使った方法で説明します。
前提条件
- ETロボコンの開発環境が構築されている
- インターネットにアクセスできる環境
手順概要
以下のような手順になります。
- CMake をインストールする
- Google Test用のフォルダを作成する
- CMakeLists.txt を作成する
- テストコードを作成する
- ビルドする
- テストを実行する
- おまけ: ビルドとテスト実行を一挙にやってくれるシェルスクリプトを作成する
CMakeをインストールする
TERMINAL上で、下記を実行しインストールします。
sudo apt install cmake
- wslのパスワードを聞かれた時は、PCにサインインした時のパスワード等をいれる。
Google Test用のフォルダを作成する
以下のようなフォルダ構成にします。
プロジェクトルート
app
standard
String.h
test
gtest
app
standard
StringTest.cpp
テスト対象は、プロジェクトルート直下のapp配下にあります。このプロジェクトルートは、TERMINAL上でpwdコマンドで表示させた場合、例えば、以下のようなフォルダになります。
/home/user001/etrobo/workspace/etrobo20220
プロジェクトルートのapp配下のフォルダ構成は、既に存在している、という前提ですので、ここで作るのは、プロジェクトルート直下のtestフォルダ配下の構成です。
gtest直下に、テスト対象と同じフォルダ構成でフォルダを作ります。
テストコードは、同一フォルダ配下にすべてのテストファイルを格納する、という考え方もありますが、テストコードを探しやすくするためには、テスト対象と同じフォルダ構成にした方が良いと考えるので、それを採用しています。
CMakeLists.txt を作成する
test/gtest 直下に下記の内容のCMakeLists.txtを作成します。
cmake_minimum_required(VERSION 3.14)
project(etrobotest)
set(CMAKE_BUILD_TYPE Debug)
# GoogleTest requires at least C++14
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
enable_testing()
include_directories($ENV{HOME}/etrobo/workspace/etrobo2023/app)
file(GLOB_RECURSE TEST_SOURCES "app/*.cpp")
add_executable(EtRoboTest ${TEST_SOURCES})
target_link_libraries(
EtRoboTest
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(EtRoboTest)
テストコードを作成する
今回のテストコードである、StringTest.cppは、下記のような内容です。記載内容は、Google Testのドキュメントで確認してください。
#include <gtest/gtest.h>
#include "standard/String.h"
// デフォルトコンストラクタのテスト
TEST(StringTest, DefaultConstructor) {
standard::String str;
// size()の結果をアサーションに含め、失敗時に値をログに出力
EXPECT_EQ(0, str.size()) << "Actual size: " << str.size();
// c_str()の結果をアサーションに含め、失敗時に値をログに出力
EXPECT_STREQ("", str.c_str()) << "Actual c_str(): '" << str.c_str() << "'";
}
// C文字列コンストラクタのテスト
TEST(StringTest, CStringConstructor) {
standard::String str("Hello");
EXPECT_STREQ("Hello", str.c_str());
}
・・・
ビルドする
test/gtest直下で、以下を実行してビルドしてください。
cmake -S . -B build
cmake --build build
正常に実行されると、test/gtest/buildフォルダが作成され、そこにビルドして作成されたファイルが格納されます。
最後は、以下のようなログが出力されていれば、正常に動作しています。
Scanning dependencies of target gmock_main
[ 90%] Building CXX object _deps/googletest-build/googlemock/CMakeFiles/gmock_main.dir/src/gmock_main.cc.o
[100%] Linking CXX static library ../../../lib/libgmock_main.a
[100%] Built target gmock_main
テストを実行する
test/gtest直下で、以下を実行してください。
cd build
ctest
正常に動作すると、以下のような表示がされます。
Test project /home/user001/etrobo/workspace/etrobo2020/test/gtest/build
Start 1: StringTest.DefaultConstructor
1/8 Test #1: StringTest.DefaultConstructor .... Passed 0.00 sec
Start 2: StringTest.CStringConstructor
2/8 Test #2: StringTest.CStringConstructor .... Passed 0.00 sec
Start 3: StringTest.CopyConstructor
3/8 Test #3: StringTest.CopyConstructor ....... Passed 0.00 sec
Start 4: StringTest.NumberConstructor
4/8 Test #4: StringTest.NumberConstructor ..... Passed 0.00 sec
Start 5: StringTest.AssignmentOperator
5/8 Test #5: StringTest.AssignmentOperator .... Passed 0.00 sec
Start 6: StringTest.Concatenation
6/8 Test #6: StringTest.Concatenation ......... Passed 0.00 sec
Start 7: StringTest.Equality
7/8 Test #7: StringTest.Equality .............. Passed 0.00 sec
Start 8: StringTest.Length
8/8 Test #8: StringTest.Length ................ Passed 0.00 sec
100% tests passed, 0 tests failed out of 8
Total Test time (real) = 0.02 sec
「100% tests passed」と出ているので、すべてのテストにパスしています。
これで、Google Test の導入は、完成です。
おまけ: ビルドとテスト実行を一挙にやってくれるシェルスクリプトを作成する
開発中、ビルドとテスト実行は頻繁に行います。
それを一挙に実施してくれるシェルスクリプトを作成しておきます。
test/gtest直下に下記のシェルスクリプトを作成してください。
gtest_build.sh
内容は、以下のようです。
#!/bin/bash
# 現在のディレクトリを保存
original_dir=$(pwd)
# test/gtest ディレクトリに移動
cd "$(dirname "$0")"
# cmake を実行
cmake -S . -B build
cmake --build build
# build ディレクトリに移動して ctest を実行
cd build && ctest
# 元のディレクトリに戻る
cd "$original_dir"
下記のように実行権を与えてください。
chmod +x gtest_build.sh
これで、gtest_build.sh を実行すると、ビルド~テスト実行までを、一挙に実施してくれます。
おわりに
Google Testの導入により、ETロボコン参加者は自分たちのコードの品質を向上させることができます。デバッガと組み合わせて使うことも容易になります。また、この先には、「テスト駆動開発(TDD)を採用」といった、より進んだ開発手法もとれるようになります。このことが、最終的には競技での成功につながるのではないかと思います。
なお、この記事通りやってもうまくできない場合は、ぜひ、コメントをください。記事をよりよいものにしていくきっかけになると思います。
参考
- 入門ガイド — Google Test ドキュメント日本語訳 (opencv.jp)
http://opencv.jp/googletestdocs/primer.html - Google Test を使ってみる(その1:準備編) | 豆蔵デベロッパーサイト (mamezou-tech.com)
https://developer.mamezou-tech.com/blogs/2022/11/04/google-test-01/ - Google Testを導入してみた #C++ - Qiita
https://qiita.com/y-vectorfield/items/6238cfd2d9c34aefe364 - Google Testの使い方 #C++ - Qiita
https://qiita.com/y-vectorfield/items/6238c
Discussion