我有课
class CSumWnd : public CBaseWnd
{
private:
bool MethodA()
}
请你能帮助如何在MethodA()
不做虚拟的情况下模拟,我不明白高性能依赖注入的概念
我有课
class CSumWnd : public CBaseWnd
{
private:
bool MethodA()
}
请你能帮助如何在MethodA()
不做虚拟的情况下模拟,我不明白高性能依赖注入的概念
这意味着您将不得不模板化您的生产代码。使用您的示例:
CSumWind
类定义:
class CSumWnd : public CBaseWnd
{
private:
bool MethodA()
};
模拟CSumWnd
类定义:
class MockCSumWnd : public CBaseWnd
{
private:
MOCK_METHOD(MethodA, bool());
};
必须使用 mocked class 测试的生产类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 步很简单。它只是文本比较和处理。
如何注入魔法 asm 来改变方法行为:(完整的源代码可在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());
}