Visual Studio 2013 MSTest with google mock and MFC(C++ Native)
MFCアプリケーションのテストにおいて、google mockを利用するまでの道のりがなかなか大変だったのでメモを公開します。 ※注意※ 結論として、MFC + MSTest + google mockは利用できない場合があります!最後までお読みください。 誰か解決方法を教えてください(笑 本記事は、以下をお考えの方にメリットがあると思います。 ・CStringやCMapなどのMFC特有のクラスに依存したクラスにおいて、google mockを利用したい方 ・Visual Studio 2013(C++/Native)でgoogle mockを利用したい方 ・C++/NativeでのUnit Testing FrameworkはMSTestが良さそうだけど、手頃で便利なMockライブラリをお探しの方 ・そんなにガリガリC++してない方 ただし、MFC + MSTest + google mockは今のところ利用できない場合があります。 実験環境は以下のようになっています。 ・Visual Studio 2013 Update4 Community Edition ・google mock 1.7.0 (https://code.google.com/p/googlemock/downloads/list)
google mockのlib化
まずはgoogle mockをlib化して、自身のテストプロジェクトから参照できるようにします。 gmock-1.7.0.zipを解凍後 gmock-1.7.0\msvc\2010\gmock.slnを開きます。 Visual Studio 2013への変換ウィザードが出ますので、「次へ」。 「ソリューションのビルド」を行います。私の環境ではビルドは通りました。 MFCアプリケーションをテストしたい方は、ここで、 gmockとgmock_main、gmock_testそれぞれに対して、 ソリューションエクスプローラーからプロジェクトプロパティを開いて、 「構成プロパティ」->「C/C++」->「コード生成」->「ランタイムライブラリ」 にて、 「マルチスレッド デバッグ DLL (/MDd)」を選択します。 (自分の作るプロジェクトと同じものを選択する、ということです。MFCの場合、/MDが必須なので/MDdにします。) ビルド後、ソリューションファイルのあるフォルダにDebugフォルダが出来て、gmock.libとgmock_main.libが出力されます。
テスト対象プロジェクトの作成
テスト対象プロジェクトを作成します。ついで、テスト対象クラスを作成します。 ここでは例によって、CCalcクラスを作りました。
#include "stdafx.h" #include "Calc.h" CCalc::CCalc() { } CCalc::~CCalc() { } int CCalc::Sum(int x, int y) { return x + y; } CString CCalc::Sum(CString x, CString y) { return x + y; }
テストプロジェクトの作成
テストプロジェクト作成
ソリューションエクスプローラーから、ソリューション右クリック =>追加 => 新規プロジェクト にて、 ネイティブ単体テスト プロジェクトを選択します。
テスト対象をリンク
・プロジェクトのプロパティを選択し、「共通プロパティ」にて、「新しい参照の追加」を選択し、同一ソリューション内のテスト対象プロジェクトを選択します。(下図参照)
・上記で作成したテストプロジェクトのプロパティを選択し、「構成プロパティ」にて、「C/C++」、「全般」にて、「追加のインクルードディレクトリ」に、テスト対象プロジェクトのヘッダーまでのパスを追加します。 ・同じく、gmockのインクルードまでのパスを追加します。(下図参照) ※gtestとgmock2つ通す必要があります。
マクロにて、ソリューションディレクトリまでは$(SolutionDir)などを利用したほうが良いと思います。
※テクニック チーム内で同じようなソリューション・プロジェクト構成を共有したい場合は、以下の様な持ち方が良いと思います。
├─GmockSampleWithMFC …テスト対象プロジェクト ├─GmockSampleWithMFC.Test …テストプロジェクト ├─include …アプリケーションで利用する外部libのinclude等を集めたフォルダ ├─include_test …テスト用includeを集めたフォルダ │ └─gmock-1.7.0 │ ├─gtest │ │ └─include ・・・ <- gmock利用時はこのincludeまでのパスを通す必要がある。 │ │ └─gtest │ │ └─internal │ └─include ・・・ <- gmock利用時はこのincludeまでのパスを通す必要がある。 │ └─gmock │ └─internal ├─lib …アプリケーションで利用する外部libを集めたフォルダ ├─lib_test …テスト用libを集めたフォルダ
・プロジェクトのプロパティを選択し、「構成プロパティ」にて、「C/C++」、「コードの生成」にて、上記gmock時と同じ「マルチスレッドデバッグ(/MDd)」を選択します。 ・プロジェクトのプロパティを選択し、「構成プロパティ」にて、「リンカー」、「全般」にて、「追加のライブラリディレクトリ」に、gmockへのパスを通します。 ・プロジェクトのプロパティを選択し、「構成プロパティ」にて、「リンカー」、「入力」にて、「追加の依存ファイル」に、「gmock.lib;gmock_main.lib」を追加します。
テストクラス作成
テスト対象
テストクラスの作り方自体は、 超入門編 — Google Mock ドキュメント日本語訳 を参考にします。
#include "stdafx.h" #include "CppUnitTest.h" #include "Calc.h" #include "gmock/gmock.h" using namespace Microsoft::VisualStudio::CppUnitTestFramework; using ::testing::Return; namespace GmockSampleWithMFCTest { class CalcMock : public ICalc { public: MOCK_METHOD2(Sum, int(int x, int y)); MOCK_METHOD2(Sum, CString(CString x, CString y)); }; TEST_CLASS(CCalcTest) { public: TEST_METHOD(SumTest) { CString szKey = _T("a"); CString szValue = _T("b"); CString ret = _T("ab"); CalcMock calc; EXPECT_CALL(calc, Sum(szKey, szValue)).WillOnce(Return(ret)); Assert::AreEqual( _T("ab"), calc.Sum(_T("a"), _T("b") )); } }; }
テスト実行
テストエクスプローラーを開きます。
テストリストが表示されますので、実行します。
ここで、何らかの要因で、テストに以下の行が必要になった場合、MSTestがうまく終了してくれません。 上記サンプルだと、下記設定は無くても動作するのですが・・・。 gtest以外のtesting frameworkからgmockを利用する際は、下記コードを追加してみよ、と書いてあったのですが。 https://code.google.com/p/googletest/wiki/AdvancedGuide
int main(int argc, char** argv) { ::testing::GTEST_FLAG(throw_on_failure) = true; ::testing::InitGoogleMock(&argc, argv); }
まとめ
以上、長くなりましたが、MFC+MSTest+gmockでした。 MSTestとの相性が、どこの時点でわるくなるのかはわかりませんが、それまでの道標としてお役に立てればと思います。