はじめに
そもそもMockって?
クラスが呼び出すクラスなりライブラリなりの代用。
テストで下位から返されるもので処理が変わったりする場合に、呼び出すモジュールの処理結果がテストで必要な結果になるよう、あれこれ操作するのは大変なので、好きな結果を返すモジュールに差し替えて動かすのがMockです。
Google Mockのセットアップ
セットアップといってもNuGetで持ってくるだけ。
「ツール -> NuGetパッケージマネージャー -> ソリューションのNuGetパッケージの管理」を選択して、管理画面を開きます。
参照タブを選択して、googlemockで検索して「googlemock.v140.windesktop.static.rt-dyn」を探します。
「googlemock.v140.windesktop.static.rt-dyn」を選択して、右側に表示されるインストールするプロジェクトの選択で、TargetProjectTestにチェックを入れてインストールします。
バージョンは最新で問題ないはずです。(現在の最新1.7.0.1)
(ちなみにgooglemockとだけ名前がついているものがありますが、ソースファイルだけ突っ込まれていて、ビルドの構成をするようなファイルは一切ないので、普通にGithubからGoogleMockのソースを持ってきて自分でビルドして使うほうが100倍マシです。)
で、バージョンは問題ないのです。
問題はNuGetのパッケージ自体に間違いがあることです。
GoogleMockのフォルダ修正
Google Mockのヘッダーファイルはgmockフォルダ下のヘッダーファイルを参照するようになっていますが、パッケージの中のフォルダはgtestになっているので、このまま使うとどう足掻いてもエラーになります。
ということで、先程ソリューションファイルがあるフォルダの直下のpackagesフォルダ内にインストールされた、GoogleMockのパッケージ内のフォルダ名を修正します。
packagesフォルダにある「googlemock.v140.windesktop.static.rt-dyn.X.X.X.X」(X.X.X.Xはインストールしたバージョン)下の「build\native\include」にある「gtest」フォルダの名前を「gmock」に変更します。
リンクの追加
package下のgmock.libをリンクする必要があるので、「構成プロパティ -> リンカー -> 入力 -> 追加の依存ファイル」にgmock.libを追加します。
以下を追加すれば、ビルド環境毎同じ設定でビルドできます。
「$(SolutionDir)packages\googlemock.v140.windesktop.static.rt-dyn.1.7.0.1\build\native\lib\$(Platform)\v140\$(Configuration)\gmock.lib」
ここまでの設定でGoogle Mockを使用できるようになります。
このままビルドしてもGoogle Mockを使っていないので、設定ができているか分からないので、簡単なテストを追加していきます。
Google Mockを使ったテストの追加
Linux環境での情報が多いですが、Google Mockの使い方自体はWindowsでも変わらないので一気にいきます。
Google Mockを使えるよう、前回のソースでテストしたメソッドとは別に、インターフェースクラスを使用する下位のクラスを使うメソッドを実装します。
インターフェースクラスの追加
少々雑ですが、TargetClass.hに追加していきます。
class InterfaceClass
{
public:
virtual ~InterfaceClass() {};
virtual int Interface() = 0;
};
インターフェースの実装クラスの追加
インターフェースクラスと同じくTargetClass.hに追加していきます。
class InheritanceClass : public InterfaceClass
{
public:
int Interface() override
{
return 1;
}
};
下位クラスを呼び出すメソッドの追加
前回作成したTargetClass.hに新しく追加します。
class TargetClass
{
public:
bool PublicMethod(int input);
bool PublicMethod2(int input);
InterfaceClass* imple_;
private:
FRIEND_TEST(TargetClassTest, PrivateMethodTest);
bool PrivateMethod(int input);
};
Mockの追加
テストの方に書くと分かりにくくなるので、TargetProjectTestにMockClass.hを追加します。
#pragma once
#include "TargetClass.h"
#include <gmock/gmock.h>
class MockClass : public InterfaceClass
{
public:
MOCK_METHOD0(Interface, int(void));
};
テストの追加
Mockを使用したテストを追加します。
using ::testing::AtLeast;
TEST(TargetClassTest, MockTest) {
TargetClass target;
MockClass *mock = new MockClass();
EXPECT_CALL(*mock, Interface()).Times(AtLeast(3));
target.imple_ = mock;
EXPECT_EQ(false, target.PublicMethod2(2));
delete target.imple_;
}
テスト追加後の各ファイル
#pragma once
#include "gtest/gtest_prod.h"
#include <memory>
class InterfaceClass
{
public:
virtual ~InterfaceClass() {};
virtual int Interface() = 0;
};
class InheritanceClass : public InterfaceClass
{
public:
int Interface() override
{
return 1;
}
};
class TargetClass
{
public:
bool PublicMethod(int input);
bool PublicMethod2(int input);
InterfaceClass* imple_;
private:
FRIEND_TEST(TargetClassTest, PrivateMethodTest);
bool PrivateMethod(int input);
};
#include "TargetClass.h"
bool TargetClass::PublicMethod(int input)
{
if (input >= 0)
{
return true;
}
return false;
}
bool TargetClass::PublicMethod2(int input)
{
if (input > imple_->Interface())
{
return true;
}
return false;
}
bool TargetClass::PrivateMethod(int input)
{
if (input <= 0)
{
return true;
}
return false;
}
#include <iostream>
#include "TargetClass.h"
int main()
{
TargetClass target;
std::cout << target.PublicMethod(1) << std::endl;
return 0;
}
#pragma once
#include "TargetClass.h"
#include <gmock/gmock.h>
class MockClass : public InterfaceClass
{
public:
MOCK_METHOD0(Interface, int(void));
};
#include "pch.h"
#include "gmock/gmock.h"
#include "TargetClass.h"
#include "MockClass.h"
using ::testing::AtLeast;
TEST(TargetClassTest, PublicMethodTest) {
TargetClass target;
EXPECT_EQ(true, target.PublicMethod(1));
EXPECT_EQ(false, target.PublicMethod(-1));
}
TEST(TargetClassTest, PrivateMethodTest) {
TargetClass target;
EXPECT_EQ(false, target.PrivateMethod(1));
EXPECT_EQ(true, target.PrivateMethod(-1));
}
TEST(TargetClassTest, ImplTest) {
TargetClass target;
target.imple_ = new InheritanceClass();
EXPECT_EQ(false, target.PublicMethod2(2));
delete target.imple_;
}
TEST(TargetClassTest, MockTest) {
TargetClass target;
MockClass *mock = new MockClass();
EXPECT_CALL(*mock, Interface()).Times(AtLeast(3));
target.imple_ = mock;
EXPECT_EQ(false, target.PublicMethod2(2));
delete target.imple_;
}
int main(int argc, char** argv) {
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}