简体   繁体   English

模拟非虚方法C ++(gmock)

[英]Mock non-virtual method C++ (gmock)

I have class 我有课

class CSumWnd : public CBaseWnd
{

 private:
 bool MethodA()
}

Please can you help how to mock MethodA() without making virtual, I didn't understand the concept of hi-perf dependency injection 请你能帮助如何模拟MethodA()而不做虚拟,我不明白hi-perf依赖注入的概念

It means you will have to templatize your production code. 这意味着您必须模拟生产代码。 Using your example: 使用你的例子:

CSumWind class definition: CSumWind类定义:

class CSumWnd : public CBaseWnd
{

 private:
 bool MethodA()
};

Mocked CSumWnd class definition: 模拟CSumWnd类定义:

class MockCSumWnd : public CBaseWnd
{

 private:
 MOCK_METHOD(MethodA, bool());
};

Production class which have to be tested with mocked class CSumWind . 生产类必须使用CSumWindCSumWind进行测试。 Now it becomes templated to provide using CSumWind class in production code and MockCSumWnd class in tests. 现在,在测试中提供在生产代码和MockCSumWnd类中使用CSumWind类的模板。

template <class CSumWndClass>
class TestedClass {
//...
   void useSumWnd(const CSumWndClass &a);

private:
  CSumWndClass sumWnd;
};

Instantiation of TestedClass in production: 在生产中实例化TestedClass

TestedClass <CSumWnd> obj;

Instantiation of TestedClass object in test executable: 测试可执行文件中TestedClass对象的实例化:

TestedClass <MockCSumWnd> testObj;

If you don't want to change the existing code, here is a specific solution for VC++ I'm working on ( https://github.com/mazong1123/injectorpp ). 如果您不想更改现有代码,这里是我正在开发的VC ++的特定解决方案( https://github.com/mazong1123/injectorpp )。 The brief steps are: 简短的步骤是:

  1. Leverage DbgHelp.h to retrieve all methods' symbols and memory addresses of a class. 利用DbgHelp.h检索类的所有方法符号和内存地址。 Basically it retrieves meta info from .pdb file at runtime. 基本上它在运行时从.pdb文件中检索元信息。
  2. Compare the user input to-mock method symbol with step 1's output, get the to-mock method's memory address. 将用户输入与模拟方法符号与步骤1的输出进行比较,获取to-mock方法的内存地址。
  3. Leverage windows api WriteProcessMemory to change the entry bytes of the to-mock method, that is something similar as: __asm {move eax, 1; 利用windows api WriteProcessMemory来改变to-mock方法的入口字节,类似于:__ asm {move eax,1; ret}. RET}。

Let's put key code here. 我们把关键代码放在这里。

  1. Retrieve methods' symbols and addresses of a class. 检索方法的符号和类的地址。 Below is the key idea of the implementation. 以下是实施的关键思路。 The full source code is availiable at https://github.com/mazong1123/injectorpp/blob/master/injectorpp/ClassResolver.cpp 完整的源代码可以在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. Step 2 is trival. 第2步很简单。 It's only text comparing and processing. 它只是文本比较和处理。

  3. How to inject the magic asm to change the method behavior: (The full source code is available at https://github.com/mazong1123/injectorpp/blob/master/injectorpp/BehaviorChanger.cpp ) 如何注入magic 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); } 

Try CppFreeMock and some others mentioned here . 试试CppFreeMock这里提到的其他一些。

Example: 例:

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());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM