はじめに
一緒に42Tokyoで勉強しているyaitoさんにGoogle testの書き方を教えてもらったので、許可を取って書き方をまとめました!
yaitoさん、ありがとうございます\(^o^)/
結論!
結論から言います。gtest
ディレクトリを作成し、gtest.cpp
というファイル名でtestを記載し、このMakefileを使えばOKです。
簡単なサンプルを記述したレポジトリを用意したので、クローンしてmake test
試してみてください。
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などのドキュメントを参考にガンガンテストを書いていけばOKです。
#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 が, 現在のスレッドで新たな失敗を生成しない |