Mock non-virtual method C++ (gmock)

匿名 (未验证) 提交于 2019-12-03 02:06:01

问题:

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

回答1:

It means you will have to templatize your production code. Using your example:

CSumWind class definition:

class CSumWnd : public CBaseWnd {   private:  bool MethodA() }; 

Mocked CSumWnd class definition:

class MockCSumWnd : public CBaseWnd {   private:  MOCK_METHOD(MethodA, bool()); }; 

Production class which have to be tested with mocked class CSumWind. Now it becomes templated to provide using CSumWind class in production code and MockCSumWnd class in tests.

template  class TestedClass { //...    void useSumWnd(const CSumWndClass &a);  private:   CSumWndClass sumWnd; }; 

Instantiation of TestedClass in production:

TestedClass  obj; 

Instantiation of TestedClass object in test executable:

TestedClass  testObj; 


回答2:

Try CppFreeMock and some others mentioned here.

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


回答3:

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). The brief steps are:

  1. Leverage DbgHelp.h to retrieve all methods' symbols and memory addresses of a class. Basically it retrieves meta info from .pdb file at runtime.
  2. Compare the user input to-mock method symbol with step 1's output, get the to-mock method's memory address.
  3. Leverage windows api WriteProcessMemory to change the entry bytes of the to-mock method, that is something similar as: __asm {move eax, 1; 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

    // 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 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. 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)

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!