Google Mockを使ってみる [Google Test]
いままで,Google Testを使ってきたが,さらにGoogle Mockも使ってみる.
Google Mockとは,まぁ日本語ドキュメントがあるので参照してください.って書いてしまうとさすがに寂しいのでもうちょっと書くというか引用すると,Google Mockは「モッククラスを作成して使用するためのライブラリ」ということになる.
で,モックというのは,「Expectation を利用して事前にプログラムされたオブジェクト」だ.呼び出されたら何を返すかとか,何を引数として呼び出されるのかとか,そもそも何回呼び出されるのかとかをあらかじめ指定しておけるオブジェクトだ.なので,テストをするときに「本物」の代わりに使うと何かと便利になる.
ではまず,Google Mockを使えるようにしてみる.Google Testを使えるようにしたときと同様に,まずは適当なディレクトリを作成し,Google Mockをダウンロード,展開してやる.
そしたらmakeする.
このとき,ubuntuの環境だとエラーが出てmakeできない.なので,1カ所変更する.
変更対象のファイルは,~/googlemock/gmock-1.6.0/make/Makefileだ.このファイルの最後の部分,-lpthreadのところを変更してやる.
変更前
変更したらmakeして,テストする.
テストでエラーが出なければOKだ.
そしたらライブラリはコピーしておく.
あと,Google Mockのパスを設定しておく.~/.bashrcとかに,
としておけばよい.
これでひとまず準備は完了.
そしたら,Google Mock ドキュメント日本語訳の超入門編に出てくるMock Turtlesの例で試してみる.
いつもと同じように適当なディレクトリにturtles_mock_projディレクトリを作って,ファイル構成は以下のようにしてやる.
それぞれのファイルは以下のようになる.ちょっと長くなるが全部示そう.
CMakeLists.txt
compiler_settings.cmake
painter.h
painter.cpp
turtle.h
mock_turtle.h
test/mock_unittest.cpp
そしたらいつも通りビルドしてやればテストできる.
コードとテストの詳細は前述のGoogle Mock ドキュメント日本語訳の超入門編をみてもらうとして,ポイントだけ説明しておく.
今回の例だと,CanDrawSomethingのテストで,PenDown()が1回だけ呼ばれることをモックを使ってテストしていて,実際,DrawCircle()でPenDown()を呼び出しているので,テストは成功する.
試しに,DrawCircle()でのPenDown()の呼び出しをコメントアウトしたりするとテストが失敗するようになるはずだ.
今回はとりあえずメソッド呼び出しの回数テストだけしか試してないけど,Google Mockの雰囲気は分かると思う.
Google Mockは他にもいろいろできるんだけど,その辺についてはまた次回.
Google Mockとは,まぁ日本語ドキュメントがあるので参照してください.って書いてしまうとさすがに寂しいのでもうちょっと書くというか引用すると,Google Mockは「モッククラスを作成して使用するためのライブラリ」ということになる.
で,モックというのは,「Expectation を利用して事前にプログラムされたオブジェクト」だ.呼び出されたら何を返すかとか,何を引数として呼び出されるのかとか,そもそも何回呼び出されるのかとかをあらかじめ指定しておけるオブジェクトだ.なので,テストをするときに「本物」の代わりに使うと何かと便利になる.
ではまず,Google Mockを使えるようにしてみる.Google Testを使えるようにしたときと同様に,まずは適当なディレクトリを作成し,Google Mockをダウンロード,展開してやる.
cd ~/ mkdir googlemock cd googlemock/ wget http://googlemock.googlecode.com/files/gmock-1.6.0.zip unzip gmock-1.6.0.zip
そしたらmakeする.
このとき,ubuntuの環境だとエラーが出てmakeできない.なので,1カ所変更する.
変更対象のファイルは,~/googlemock/gmock-1.6.0/make/Makefileだ.このファイルの最後の部分,-lpthreadのところを変更してやる.
変更前
変更後gmock_test : gmock_test.o gmock_main.a $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
gmock_test : gmock_test.o gmock_main.a $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -lpthread -o $@
変更したらmakeして,テストする.
cd gmock-1.6.0/make/ make ./gmock_test
テストでエラーが出なければOKだ.
そしたらライブラリはコピーしておく.
cd ~/googlemock/gmock-1.6.0/ mkdir lib cp make/gmock_main.a lib/libgmock_main.a
あと,Google Mockのパスを設定しておく.~/.bashrcとかに,
export GMOCK_DIR=~/googlemock/gmock-1.6.0
としておけばよい.
これでひとまず準備は完了.
そしたら,Google Mock ドキュメント日本語訳の超入門編に出てくるMock Turtlesの例で試してみる.
いつもと同じように適当なディレクトリにturtles_mock_projディレクトリを作って,ファイル構成は以下のようにしてやる.
turtles_mock_proj/ ├── CMakeLists.txt ├── compiler_settings.cmake ├── mock_turtle.h ├── painter.cpp ├── painter.h ├── test │ └── mock_unittest.cpp └── turtle.h
それぞれのファイルは以下のようになる.ちょっと長くなるが全部示そう.
CMakeLists.txt
cmake_minimum_required(VERSION 2.6) project(mock_test) include (compiler_settings.cmake) enable_testing() set(CMAKE_INCLUDE_CURRENT_DIR ON) message(STATUS GTEST_DIR=$ENV{GTEST_DIR}) message(STATUS GMOCK_DIR=$ENV{GTEST_DIR}) include_directories($ENV{GTEST_DIR}/include) include_directories($ENV{GMOCK_DIR}/include) link_directories($ENV{GTEST_DIR}/lib) link_directories($ENV{GMOCK_DIR}/lib) cxx_gmock_test(mock_test "" painter.cpp test/mock_unittest.cpp)
compiler_settings.cmake
# compiler settings find_package(Threads) set(cxx_base_flags "${cxx_base_flags} -Wall -Wshadow") set(cxx_base_flags "${cxx_base_flags} -Wextra") set(cxx_base_flags "${cxx_base_flags} -Werror") function(cxx_executable_with_flags name cxx_flags libs) add_executable(${name} ${ARGN}) if (cxx_flags) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") endif() foreach (lib "${libs}") target_link_libraries(${name} ${lib}) endforeach() endfunction() function(cxx_executable name libs) cxx_executable_with_flags(${name} "${cxx_base_flags}" "${libs}" ${ARGN}) endfunction() function(cxx_test_with_flags name cxx_flags libs) cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) target_link_libraries(${name} gtest;gtest_main) target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) add_test(${name} ${name}) endfunction() function(cxx_test name libs) cxx_test_with_flags("${name}" "${cxx_base_flags}" "${libs}" ${ARGN}) endfunction() function(cxx_gmock_test name libs) cxx_test_with_flags("${name}" "${cxx_base_flags}" "${libs};gmock_main" ${ARGN}) endfunction()
painter.h
#ifndef PAINTER_H #define PAINTER_H #include "turtle.h" class Painter { public: Painter(Turtle* turtle) : turtle_(turtle) {} ~Painter() {} bool DrawCircle(int x, int y, int r); private: Turtle* turtle_; }; #endif // PAINTER_H
painter.cpp
#include "painter.h" bool Painter::DrawCircle(int x, int y, int r) { (void)x; (void)y; (void)r; turtle_->PenDown(); return true; }
turtle.h
#ifndef TURTLE_H #define TURTLE_H class Turtle { public: Turtle() {} virtual ~Turtle() {} virtual void PenUp() = 0; virtual void PenDown() = 0; virtual void Forward(int distance) = 0; virtual void Turn(int degrees) = 0; virtual void GoTo(int x, int y) = 0; virtual int GetX() const = 0; virtual int GetY() const = 0; }; #endif // TURTLE_H
mock_turtle.h
#ifndef MOCK_TURTLE_H #define MOCK_TURTLE_H #include "gmock/gmock.h" #include "turtle.h" class MockTurtle : public Turtle { public: MOCK_METHOD0(PenUp, void()); MOCK_METHOD0(PenDown, void()); MOCK_METHOD1(Forward, void(int distance)); MOCK_METHOD1(Turn, void(int degrees)); MOCK_METHOD2(GoTo, void(int x, int y)); MOCK_CONST_METHOD0(GetX, int()); MOCK_CONST_METHOD0(GetY, int()); }; #endif // MOCK_TURTLE_H
test/mock_unittest.cpp
#include "gtest/gtest.h" #include "gmock/gmock.h" #include "painter.h" #include "mock_turtle.h" TEST(PainterTest, CanDrawSomething) { MockTurtle turtle; EXPECT_CALL(turtle, PenDown()) .Times(::testing::AtLeast(1)); Painter painter(&turtle); EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); }
そしたらいつも通りビルドしてやればテストできる.
コードとテストの詳細は前述のGoogle Mock ドキュメント日本語訳の超入門編をみてもらうとして,ポイントだけ説明しておく.
今回の例だと,CanDrawSomethingのテストで,PenDown()が1回だけ呼ばれることをモックを使ってテストしていて,実際,DrawCircle()でPenDown()を呼び出しているので,テストは成功する.
試しに,DrawCircle()でのPenDown()の呼び出しをコメントアウトしたりするとテストが失敗するようになるはずだ.
今回はとりあえずメソッド呼び出しの回数テストだけしか試してないけど,Google Mockの雰囲気は分かると思う.
Google Mockは他にもいろいろできるんだけど,その辺についてはまた次回.
タグ:Google Mock