Google Testの使い方

# Google Testの使い方

## Google Testとは

正式にはGoogle C++ Testing Frameworkというそうで、Googleが提供するC++用の単体テストの自動実行を可能にするフレイムワークです。

## 単体テストに関して

### そもそも単体テストって何?

単体テストは、プログラムを構成する比較的小さな単位が個々の機能を正しく果たしているかどうかを検証するテストです。

### 私のようにアカデミックで働いている人間が研究の中で単体テストなんてやる必要あるのか？

**必要あります。**

単体テストとは文字通りプログラムの部品ごとにその機能をチェックすることです。言い換えれば、単体テストをするためには部品ごとに分解可能なプログラムでなければなりません。残念ながら、アカデミックで作成されたコードのほとんどは、特にコンピュータサイエンスの分野を除き、**分解可能という基準を満たしていません。**

私のいる学部の先生で、[Sandia National Laboratories](http://www.sandia.gov/)で7年間研究していた方曰く、

> 99% of academic codes is *SHIT*!!!
> （学究分野で作られたコードの99%はクソだ！）

だそうですw

実際、他学生の作ったコードを再利用して研究をしようとしたとき、ある機能を別の機能に入れ替えたくてもコードがお互いに関係しすぎていてほとんど不可能ということが往々にしてあります。（実は今まさにそんな状況です）

単体テストを行う場合、機能が関数やクラス単位で明確に分離されていなければならず、単体テストを行いながらコードを書いていくことで結果的に綺麗な構造を持ったコードが作られます。綺麗なコードができるということは読みやすいということで、他の人との連携も取りやすくなります。


## 利用方法

[GoogleTest User's Guide - Quickstart: Building with CMake](https://google.github.io/googletest/quickstart-cmake.html)にCMakeでGoogleTestを用いる方法が書いてあります。

CMakeでGoogleTestを用いるには大きく分けて以下の4つの方法がありますが、公式ドキュメントには4番目の方法が記載されています。

1. Googlet Testを手動でダウンロードしてビルドし利用する。
2. Google Testをプロジェクト内にコピーして利用する。
3. Google Testをgit submoduleに加えて利用する。
4. CMakeのconfigureの一環として自動でGoogle Testをダウンロードして利用する。

### Google Testを手動でダウンロードして利用する方法

#### Google Testのダウンロード

Githubにある[Google Testのレポジトリ](https://github.com/google/googletest/releases)から最新リリースをダウンロードします。ここでは`~/Downloads`で作業することにします。2025年1月2日現在の最新バージョンは1.15.2です。

````
$ cd ~/Downloads
$ wget https://github.com/google/googletest/archive/refs/tags/v1.15.2.zip
$ unzip googletest-1.15.2.zip
````

これで`googletest-1.15.2`というディレクトリができます。

#### Google Testのビルドとインストール

CMakeとNinjaを事前にインストールしておきましょう。CMake 3.13以上なら下記コマンドでビルドおよびインストールができます。

```terminal
$ cd googletest-1.15.2
$ cmake -S . -B build -G Ninja
$ cmake --build build
$ cmake --install build
```

管理者権限がなく、ローカルディレクトリにインストールする場合は、`CMAKE_INSTALL_PREFIX`でインストールするディレクトリを指定することができます。

```terminal
$ cmake -S . -B build -G Ninja -DCMAKE_INSTALL_PREFIX=$HOME/.local 
```

#### テストへリンク

CMakeで`find_package(GTest REQUIRED)`を使えば簡単にGoogle Testを自分のプログラムにリンクできます。

```cmake
cmake_minimum_required(VERSION 3.14)
project(cmake_example)

find_package(GTest REQUIRED)

enable_testing()

add_executable(
  mytest
  mytest.cpp
)
target_link_libraries(
  mytest
  GTest::gtest_main
)

include(GoogleTest)
gtest_discover_tests(mytest)
```


### CMakeのconfigureの中で自動でGoogle Testをダウンロードさせて利用する方法

CMakeの[FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html)というモジュールを使います。例えばmylibというプロジェクトがあるとします。Google Testを自動でダウンロードするには`CMakeLists.txt`で単体テストを定義する前に以下のスクリプトを追加します。

```cmake
# GoogleTestをダウンロード
include(FetchContent)
FetchContent_Declare(
  googletest
  URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# Google Testの不要なキャッシュ変数をオフにしておく
set(BUILD_GMOCK CACHE BOOL OFF "" FORCE)
set(INSTALL_GTEST CACHE BOOL OFF "" FORCE)
# 親プロジェクトのコンパイラ・リンカ設定を上書きするのを防ぐ（Windowsのみ）
if(WIN32)
  set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif()
# googletestをターゲットとして使えるようにする
FetchContent_MakeAvailable(googletest)
```

そして単体テストを定義するCMakeスクリプトは以下のように書きます。

```cmake
enable_testing()

# 単体テストの定義
add_executable(
  mylibtest
  mylibtest.cpp
)
target_link_libraries(
  mylibtest
  mylib
  GTest::gtest_main
)
# GoogleTestはC++14以上が必要
target_compile_features(
  mylibtest
  PUBLIC
  cxx_std_14
)

include(GoogleTest)
gtest_discover_tests(MyLibTest)
```



## 使用方法

[GoogleTest User's Guide](https://google.github.io/googletest/)を参照してください。

### ざっくりした説明

テスト用ソースコードに`gtest/gtest.h`をインクルードします。

````cpp:test.cpp
#include <gtest/gtest.h>
````



テストケースを作成します。テストケースの作成方法は

- TEST()マクロを利用する。
- テストフィクスチャを作りTEST_F()マクロを利用する。

の2つがあります。テストフィクスチャは複数のテスト間で同じデータを使用するときに使います。

````cpp:test.cpp
#include <gtest/gtest.h>

// TESTマクロを使う場合

// 第1引数がテストケース名、第2引数がテスト名
TEST(MyLibraryTest, Function1Test) {
    ...
}

TEST(MyLibraryTest, Class1Test) {
    ...
}
````

````cpp:test.cpp
#include <gtest/gtest.h>

// テストフィクスチャとTEST_Fマクロを使う場合

class MyLibraryTest : public ::testing::Test {
  protected:
    // データメンバーの初期化
    void SetUp() override {
        data1_ = 2.0;
    }
    // データメンバー
    double data1_;
}

// テストフィクスチャを使うには、テストケース名とテストフィクスチャ名が一致していなければならない。
TEST_F(MyLibraryTest, Function1Test) {
    double result = Function1(data1_); // data1_にアクセスできる
    ...
}

TEST_F(MyLibraryTest, Class1Test) {
    Class1 obj(data1_); // data1_にアクセスできる
    ...
}
````