ソフトな忘却力(15) VSCodeでctest+gtest、CMakeLists.txt

Joseph Halfmoon

前回 CMakeLists.txtを書くだけで、GoogleTestがインストールされていなくても速攻でgtestできるのに感激しました。CMake本当に便利。しかし前回はVSCodeからリモート接続じゃなかったです。それに全部のファイルを同じディレクトリに入れてました。やっぱりライブラリやテストは分けたいです。またテキトーにCMakeLists.txt書いてみたら通ってしまった。これで良いの?

開発というほどの開発などしないのですが、最近、基本VSCodeです。VSCodeはWindows機で動かしていますが、Raspberry Piにリモート接続して「開発」していることが多いです。今回も同様であります。

さて、前回、GoogleTestをインストールしてなかったラズパイ3でも、CMakeLists.txtを書くだけでgtestできる(cmakeがプロジェクトローカルにgtestをセットしてくれる)という機能に感激しました。しかし、gtestするためだけのディレクトリ構成で全然実用的じゃなかったです。

冒頭のアイキャッチ画像に実際に作製したツリーの様子を掲げましたが、ソースツリーは最低線以下くらいにしたいです。

  • プロジェクトルート mainのソースを含む本体コード群を置く
    • lib ライブラリを構成するコード群を置く
    • include 上記のライブラリなどを参照するときに使うヘッダ群を置く
    • test 単体テスト用のコード群を置く
3つのCMakeLists.txtファイル

ソースが入っているディレクトリが3個あるので、CMakeLists.txtファイルも3個必要です。プロジェクトルートのCMakeLists.txtファイルは、VSCodeのCMake Toolsの自動生成機能で作ったものに手を入れました。こんな感じ。

cmake_minimum_required(VERSION 3.0.0)
project(gtest000 VERSION 0.1.0)

include(CTest)
enable_testing()

add_executable(gtest000 main.cpp)
add_subdirectory(lib)
add_subdirectory(test)
target_link_libraries(gtest000 func)

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

上記で手を入れたのは以下の3行だけです。これはディレクトリ構造と、リンクするライブラリの指定なのでショウガナイ。

add_subdirectory(lib)
add_subdirectory(test)
target_link_libraries(gtest000 func)

CTest使うぞなど、最初からツール様の言う通り。

2番目の CMakeLists.txt は、ライブラリをビルドするためのlibディレクトリに入れたもの。これは第4回で作ってあったものをほぼほぼ流用。全然 C++ なコードでないんだけれども 今回はCXX指定。

cmake_minimum_required(VERSION 3.16.3)
project(libfunc
    VERSION 0.1.0
    LANGUAGES CXX)

add_library(func func.cpp)

3番目の CMakeLists.txt は、TESTディレクトリに入れて、単体テスト用の実行ファイルをビルドするためのもの。これは前回のものをほぼほぼ流用。変更点は、ファイル名の違いと、上で生成されるライブラリをリンクするように指定したところ。

cmake_minimum_required(VERSION 3.14)
project(gtestSub)
set(CMAKE_CXX_STANDARD 11)

include(FetchContent)
FetchContent_Declare(
    googletest
    URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

enable_testing()

add_executable(
    test000
    test000.cpp
)

target_link_libraries(
    test000
    func
    gtest_main
)

include(GoogleTest)
gtest_discover_tests(test000)
ソースコードとヘッダ

念のため意味無しのソースとヘッダも書いておきます。

まずは、プロジェクトルートにおいた main.cpp。Hello, world.の「隙間」にライブラリ内の関数を無理やり押し込んだだけ。

#include <iostream>
#include "include/func.h"

int main(int, char**) {
    std::cout << func1(1, 2) << "Hello, world!\n";
}

ライブラリのソースファイル。しょうもない、極小、C++じゃねえ。

int func1(int a, int b) {
    return a * b;
}

ライブラリのヘッダファイル。

#ifndef FUNC_H
#define FUNC_H

int func1(int a, int b);

#endif /* FUNC_H */

そして単体テストのソースであります。

#include <gtest/gtest.h>
#include "../include/func.h"

TEST(func1, BasicTest) {
    EXPECT_EQ( func1(3, 4), 12); //GOOD
    EXPECT_EQ( func1(1, 1), 1);  //GOOD
}
ビルドして実行

VSCodeの下の方にあるステータスバーのbuildボタンを押せば、全てがビルドされるのであります。

  • ライブラリlibfunc.aおよび、gtestに必要なライブラリ全て
  • 単体テストの実行ファイル
  • アプリ本体の実行ファイル

まずは、buildディレクトリ配下のtestディレクトリに生成されている単体テストのファイルを直接実行してみました。

directTest

前回同様、gtest のレポートが現れます。
続いて、CMakeのテストランナーである ctest をコマンドラインから呼び出してみました。こんな感じ。
cliCtest
出力形式こそ違え、同じテストがちゃんと走っているみたいです。

最後に、VSCodeの下のステータスラインにある Run Ctestのボタンを押してみました。

guiCtest
結果が出力ウインドウに出てくるだけではなく、Run Ctestのボタンが消えて、代わりにチェックマーク(上の画面の右下)が出てまいりました。

1/1 test passing とな

意外と簡単に ctest + gtest を VSCode(リモート)から動かせてしまった。本当にこんなんで良いのか。また後で落とし穴を見つけるのではないかと心配。

ソフトな忘却力(14) ラズパイでgtest、CMakeLists.txt書くだけでOK に戻る

ソフトな忘却力(16) VSCodeで ctest+gtest その2、Classのテスト へ進む