C++やC言語作ったライブラリをテストしたいときに、GoogleTestを使ってテストを書くことができます。
名前の通り、googleが作ったテストフレームワークです。
サンプルコード
まずは、どのような感じでテストが書けるのか紹介します。
たとえば次のようなコードがあるとします。
include/myint.h
class MyInt
{
public:
MyInt(int num);
bool isOdd();
bool isEven();
private:
int num_;
};
src/myint.cpp
#include <myint.h>
MyInt::MyInt(int num)
:num_(num)
{}
bool MyInt::isOdd()
{
// 奇数かどうかを判定する
return (num_ % 2) != 0 ? true : false;
}
bool MyInt::isEven()
{
return isOdd(); // 例として、ここにバグがある
}
すると、テストは次のように書けます。
test/gtest_myint.cpp
#include "gtest/gtest.h"
#include "myint.h"
namespace {
class MyIntTest : public ::testing::Test{};
TEST_F(MyIntTest, isOdd)
{
MyInt mi1 = MyInt(10);
EXPECT_EQ(false, mi1.isOdd());
MyInt mi2 = MyInt(13);
EXPECT_EQ(true, mi2.isOdd());
}
TEST_F(MyIntTest, isEven)
{
MyInt mi1 = MyInt(10);
EXPECT_EQ(true, mi1.isEven());
MyInt mi2 = MyInt(13);
EXPECT_EQ(false, mi2.isEven());
}
} // namespace
このようなテストを書いた場合、GoogleTestをビルドしてからテストのビルドを行います。
GoogleTestのビルド
GoogleTestのコードは次のようにして取得できます。
git clone git@github.com:google/googletest.git
OSX(Yosemite)でのビルド
CXX=/usr/bin/clang++ CC=/usr/bin/clang ./configure 'CXXFLAGS=-std=c++11 -stdlib=libc++'
CXX=/usr/bin/clang++ CC=/usr/bin/clang make
Ubuntu(14.04)でのビルド
cmakeを使います。
sudo apt-get install cmake
mkdir build
cd build
cmake ..
make
テストのビルド
たとえば次のようなディレクトリ構成の場合、したのようなMakefileが書けると思います。
テストをビルドする際にgtestも合わせてビルドすることになります。
.
├── LICENSE
├── README.md
├── include
│ └── myint.h
├── extsrc
│ └── googletest/googletest
├── make
│ └── Makefile
├── src
│ └── myint.cpp
├── test
└── gtest_myint.cpp
ディレクトリ名等は適宜読み替えてください。
Makefile
SRC_DIR=../src
INC_DIR=../include
TEST_DIR=../test
LIB_DIR=../lib
BIN_DIR=../bin
OBJ_DIR=./obj
GTEST_DIR=../extsrc/googletest/googletest
INCS += -I$(INC_DIR)
UNAME := $(shell uname -s)
ifeq ($(UNAME),Linux)
CXX=g++
endif
ifeq ($(UNAME),Darwin)
CXX=/usr/bin/clang++
endif
CXXFLAGS = -g -Wall
SRCS = $(SRC_DIR)/myint.cpp
TARGET = $(LIB_DIR)/libmyint.a
OBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(SRCS:.cpp=.o)))
default: $(TARGET)
.PHONY: default
$(TARGET): $(OBJS)
@[ -d $(LIB_DIR) ] || mkdir -p $(LIB_DIR)
$(AR) ruc $(TARGET) $(OBJS)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
@[ -d $(OBJ_DIR) ] || mkdir -p $(OBJ_DIR)
$(CXX) $(CXXFLAGS) $(INCS) -o $@ -c $<
TEST_SRCS = $(TEST_DIR)/gtest_myint.cpp
TEST_TARGET = $(BIN_DIR)/gtest_myint
TEST_OBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(TEST_SRCS:.cpp=.o)))
LIBS += -L$(LIB_DIR)
LIBS += -lmyint
CPPFLAGS += -isystem $(GTEST_DIR)/include
CXXFLAGS = -g -Wall -Wextra -pthread
# All Google Test headers. Usually you shouldn't change this
# definition.
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
$(GTEST_DIR)/include/gtest/internal/*.h
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
# For simplicity and to avoid depending on Google Test's
# implementation details, the dependencies specified below are
# conservative and not optimized. This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
$(OBJ_DIR)/gtest-all.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
-o $@ $(GTEST_DIR)/src/gtest-all.cc
$(OBJ_DIR)/gtest_main.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
-o $@ $(GTEST_DIR)/src/gtest_main.cc
$(LIB_DIR)/gtest.a : $(OBJ_DIR)/gtest-all.o
$(AR) $(ARFLAGS) $@ $^
$(LIB_DIR)/gtest_main.a : $(OBJ_DIR)/gtest-all.o $(OBJ_DIR)/gtest_main.o
$(AR) $(ARFLAGS) $@ $^
test: $(TEST_TARGET)
.PHONY: test
$(TEST_TARGET): $(TARGET) $(TEST_OBJS) $(LIB_DIR)/gtest_main.a
@[ -d $(BIN_DIR) ] || mkdir -p $(BIN_DIR)
$(CXX) $(LDFLAGS) -o $@ $(TEST_OBJS) \
$(LIB_DIR)/gtest_main.a $(LIBS) -lpthread
$(OBJ_DIR)/%.o: $(TEST_DIR)/%.cpp $(GTEST_HEADERS)
@[ -d $(OBJ_DIR) ] || mkdir -p $(OBJ_DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCS) -o $@ -c $<
clean:
rm -f $(TARGET) $(TEST_TARGET) $(OBJS) $(TEST_OBJS)
これで、Makefileがあるディレクトリにおいて
make
make test
とやるとライブラリとテストがビルドできます。
テストの実行と結果確認
上の例では binディレクトリに gtest_myint というバイナリができているので、それを実行すると、
$ ./gtest_myint
Running main() from gtest_main.cc
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from MyIntTest
[ RUN ] MyIntTest.isOdd
[ OK ] MyIntTest.isOdd (0 ms)
[ RUN ] MyIntTest.isEven
../test/gtest_myint.cpp:21: Failure
Value of: mi1.isEven()
Actual: false
Expected: true
../test/gtest_myint.cpp:24: Failure
Value of: mi2.isEven()
Actual: true
Expected: false
[ FAILED ] MyIntTest.isEven (0 ms)
[----------] 2 tests from MyIntTest (0 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran. (0 ms total)
[ PASSED ] 1 test.
[ FAILED ] 1 test, listed below:
[ FAILED ] MyIntTest.isEven
1 FAILED TEST
という感じでテストが失敗することが確認できます。
修正してビルドしなおせばもちろん全てOKになります。
まとめ
GoogleTestを使えばC++のテストが上のような感じでかけます。
慣れるまではMakefileを書く部分でハマったりしますが、一度環境を作ればテストを書くのは比較的簡単だと思います。
テストの書き方などは
googletest/Primer.md at master · google/googletest
が参考になると思います。
今回のコードは、
にあります。