Makefileに書くだけでOK！ C++で簡単にGoogle testを始めよう

# はじめに

一緒に42Tokyoで勉強しているyaitoさんにGoogle testの書き方を教えてもらったので、許可を取って書き方をまとめました！

yaitoさん、ありがとうございます＼(^o^)／

## 結論！

結論から言います。`gtest`ディレクトリを作成し、`gtest.cpp`というファイル名でtestを記載し、このMakefileを使えばOKです。

簡単なサンプルを記述したレポジトリを用意したので、クローンして`make test`試してみてください。

[kohkubo/google_test_sample](https://github.com/kohkubo/google_test_sample)

## Makefile

```Makefile
gtestdir	=	./test
gtest		=	$(gtestdir)/gtest $(gtestdir)/googletest-release-1.11.0

testdir = ./gtest

$(gtest):
	curl -OL https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz
	tar -xvzf release-1.11.0.tar.gz googletest-release-1.11.0
	$(RM) -rf release-1.11.0.tar.gz
	python googletest-release-1.11.0/googletest/scripts/fuse_gtest_files.py $(gtestdir)
	mv googletest-release-1.11.0 $(gtestdir)

test_compile = clang++ -std=c++11 \
	$(testdir)/gtest.cpp $(gtestdir)/googletest-release-1.11.0/googletest/src/gtest_main.cc $(gtestdir)/gtest/gtest-all.cc \
	-I$(gtestdir) -I$(includes) -lpthread -o tester

.PHONY: test
test: $(gtest)
	$(test_compile)
	./tester # --gtest_filter=Vector.other
```

## testの書き方

後は[Googletest Primer | GoogleTest](https://google.github.io/googletest/primer.html)などのドキュメントを参考にガンガンテストを書いていけばOKです。

```cpp
#include <gtest/gtest.h>
#include <vector>

TEST(Vector, Constructor) {
  std::vector<int> v;
  EXPECT_EQ(v.size(), 0);
  EXPECT_EQ(v.size(), 1);
}
```

## Makefileで行っていること

google testのレポジトリをクローンしてきて、用意された`fuse_gtest_files.py`を実行しています。

Google testの実装は、約30個のファイルから構成されています。それらを一括して使える`gtest/gtest.h`、`gtest-all.cc`と作成してくれるスクリプトが最初から用意されています。

```
python fuse_gtest_files.py OUTPUT_DIR
```

で指定したディレクトリにファイルを用意してくれます。

これらをコンパイルに巻き込むことで、簡単にtestを実行してくれます。


## テスト用おすすめコンパイルオプション

C言語では、clangにコンパイルをオプションをつけることで、実行結果以外のエラーを検出することができます。
system関数とleaksコマンド、デストラクタを使用したリークチェックは実行に時間が掛かるので、`brew install llvm`をして、`-fsanitize=leak`を使うのがおすすめです。

おすすめのオプションです。一度に設定することもできます。

| オプション | 説明 |
| - | - |
| -fsanitize=address | buffer overflowなど、アドレス関係のバグチェック |
| -fsanitize=leak | freeし忘れなど、メモリリークのチェック |
| -fsanitize=undefined | 動作が保証されない書き方をチェック |

動的チェックのため、**実行時間が遅くなることには注意**です。

## アサーションの種類

他にもいろいろありますが、主なものを紹介します。

|致命的なアサーション|致命的ではないアサーション|検証内容|
|:----|:----|:----|
|ASSERT_TRUE(condition);|EXPECT_TRUE(condition);|condition が true|
|ASSERT_FALSE(condition);|EXPECT_FALSE(condition);|condition が false|
|ASSERT_EQ(expected, actual);|EXPECT_EQ(expected, actual);|expected == actual|
|ASSERT_NE(val1, val2);|EXPECT_NE(val1, val2);|val1 != val2|
|ASSERT_LT(val1, val2);|EXPECT_LT(val1, val2);|val1 < val2|
|ASSERT_LE(val1, val2);|EXPECT_LE(val1, val2);|val1 <= val2|
|ASSERT_GT(val1, val2);|EXPECT_GT(val1, val2);|val1 > val2|
|ASSERT_GE(val1, val2);|EXPECT_GE(val1, val2);|val1 >= val2|
|ASSERT_STREQ(expected_str, actual_str);|EXPECT_STREQ(expected_str, actual_str);|2つの C 文字列の内容が等しい|
|ASSERT_STRNE(str1, str2);|EXPECT_STRNE(str1, str2);|2つの C 文字列の内容が等しくない|
|ASSERT_STRCASEEQ(expected_str, actual_str);|EXPECT_STRCASEEQ(expected_str, actual_str);|大文字小文字を無視した場合，2つの C 文字列の内容が等しい|
|ASSERT_STRCASENE(str1, str2);|EXPECT_STRCASENE(str1, str2);|大文字小文字を無視した場合，2つの C 文字列の内容が等しくない|
|ASSERT_THROW(statement, exception_type);|EXPECT_THROW(statement, exception_type);|statement が与えられた型の例外を投げる|
|ASSERT_ANY_THROW(statement);|EXPECT_ANY_THROW(statement);|statement が任意の型の例外を投げる|
|ASSERT_NO_THROW(statement);|EXPECT_NO_THROW(statement);|statement が例外を投げない|
|ASSERT_FLOAT_EQ(expected, actual);|EXPECT_FLOAT_EQ(expected, actual);|2つの float 値が，ほぼ等しい|
|ASSERT_DOUBLE_EQ(expected, actual);|EXPECT_DOUBLE_EQ(expected, actual);|2つの double 値が，ほぼ等しい|
|ASSERT_NEAR(val1, val2, abs_error);|EXPECT_NEAR(val1, val2, abs_error);|val1 と val2 の差が，与えられた絶対誤差以内に収まる|
|ASSERT_DEATH(statement, regex);|EXPECT_DEATH(statement, regex);|与えられたエラーが発生し，statement がクラッシュ|
|ASSERT_DEATH_IF_SUPPORTED(statement, regex);|EXPECT_DEATH_IF_SUPPORTED(statement, regex);|Death テストがサポートされていれば，statement が与えられたエラーでクラッシュすることを検証し，そうでなければ何もしない|
|ASSERT_EXIT(statement, predicate, regex);|EXPECT_EXIT(statement, predicate, regex);|statement が与えられたエラーで終了し，終了コードが predicate にマッチする|
|ASSERT_NO_FATAL_FAILURE(statement);|EXPECT_NO_FATAL_FAILURE(statement);|statement が， 現在のスレッドで新たな失敗を生成しない|


## 参考

[1分で実行できる？インストール不要、C言語向けGoogleTestサンプル for Linux - Qiita](https://qiita.com/igayu/items/9ff003309b237e9ae116)

[上級ガイド — Google Test ドキュメント日本語訳](http://opencv.jp/googletestdocs/advancedguide.html)