授業がある
class CSumWnd : public CBaseWnd
{
private:
bool MethodA()
}
MethodA()
仮想化せずにモックする方法を教えてください、私はhi-perf依存性注入の概念を理解していませんでした
授業がある
class CSumWnd : public CBaseWnd
{
private:
bool MethodA()
}
MethodA()
仮想化せずにモックする方法を教えてください、私はhi-perf依存性注入の概念を理解していませんでした
これは、本番コードをテンプレート化する必要があることを意味します。あなたの例を使用して:
CSumWind
クラス定義:
class CSumWnd : public CBaseWnd
{
private:
bool MethodA()
};
モックCSumWnd
クラス定義:
class MockCSumWnd : public CBaseWnd
{
private:
MOCK_METHOD(MethodA, bool());
};
モッククラスでテストする必要がある本番クラスCSumWind
。CSumWind
これで、本番コードでMockCSumWnd
クラスを使用し、テストでクラスを使用するようにテンプレート化されます。
template <class CSumWndClass>
class TestedClass {
//...
void useSumWnd(const CSumWndClass &a);
private:
CSumWndClass sumWnd;
};
生産中のインスタンスTestedClass
化:
TestedClass <CSumWnd> obj;
TestedClass
テスト実行可能ファイル内のオブジェクトのインスタンス化:
TestedClass <MockCSumWnd> testObj;
既存のコードを変更したくない場合は、私が取り組んでいるVC ++の特定のソリューションを次に示します(https://github.com/mazong1123/injectorpp)。簡単な手順は次のとおりです。
ここにキーコードを入れましょう。
クラスのメソッドのシンボルとアドレスを取得します。以下は、実装の重要なアイデアです。完全なソースコードはhttps://github.com/mazong1123/injectorpp/blob/master/injectorpp/ClassResolver.cppで入手できます。
// Retrieve class symbol.
if (SymGetTypeFromName(this->m_hProcess, modBase, className.c_str(), classSymbol) == FALSE)
{
throw;
}
// Get children of class - which are methods.
DWORD numChildren = 0;
if (SymGetTypeInfo(this->m_hProcess, classSymbol->ModBase, classSymbol->TypeIndex, TI_GET_CHILDRENCOUNT, &numChildren) == FALSE)
{
throw;
}
// Get methods info.
if (SymGetTypeInfo(this->m_hProcess, classSymbol->ModBase, classSymbol->TypeIndex, TI_FINDCHILDREN, methods) == FALSE)
{
throw;
}
// Retrieve all methods.
for (DWORD i = 0; i < numChildren; ++i)
{
ULONG curChild = methods->ChildId[i];
// Resolve function.
Function resolvedFunction;
this->m_functionResolver->Resolve(classSymbol->ModBase, curChild, resolvedFunction);
// Add the resolved function to the output.
resolvedMethods.push_back(resolvedFunction);
}
ステップ2は些細なことです。テキストの比較と処理のみです。
メソッドの動作を変更するためにマジックアセンブリを注入する方法:(完全なソースコードはhttps://github.com/mazong1123/injectorpp/blob/master/injectorpp/BehaviorChanger.cppで入手できます)
// A magic function to change the function behavior at runtime
//
// funcAddress - The address of the function to be changed from.
// expectedReturnValue - The return value should be changed to.
void BehaviorChanger::ChangeFunctionReturnValue(ULONG64 funcAddress, int expectedReturnValue)
{
// The purpose of this method is to change the return value
// to what ever int value we expected.
// Therefore, we just need to inject below asm to the header of specific function:
//
// mov eax, expectedValue
// ret
//
// Above asm code tells the function to return expectedValue immediately.
// Now let's prepare the asm command.
byte asmCommand[6];
// mov
asmCommand[0] = 0xB8;
// The value.
asmCommand[1] = expectedReturnValue & 0xFF;
asmCommand[2] = (expectedReturnValue >> 8) & 0xFF;
asmCommand[3] = (expectedReturnValue >> 16) & 0xFF;
asmCommand[4] = (expectedReturnValue >> 24) & 0xFF;
// ret
asmCommand[5] = 0xC3;
WriteProcessMemory((HANDLE)-1, (void*)funcAddress, asmCommand, 6, 0);
}
CppFreeMockとここで言及されている他のいくつかを試してみてください。
例:
string func() {
return "Non mocked.";
}
TEST(HelloWorld, First) {
EXPECT_CALL(*MOCKER(func), MOCK_FUNCTION()).Times(Exactly(1))
.WillOnce(Return("Hello world."));
EXPECT_EQ("Hello world.", func());
}