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

时间:2011-04-25 11:05:23

标签: c++ mocking gmock

我有课

class CSumWnd : public CBaseWnd
{

 private:
 bool MethodA()
}

请你能帮助如何模拟MethodA()而无需虚拟, 我不明白hi-perf dependency injection

的概念

3 个答案:

答案 0 :(得分:14)

这意味着您必须对生产代码进行模板化。使用您的示例:

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;

答案 1 :(得分:1)

尝试CppFreeMock,其他人提及here

示例:

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

答案 2 :(得分:1)

如果您不想更改现有代码,这里是VC ++的特定解决方案我正在处理(https://github.com/mazong1123/injectorpp)。简短的步骤是:

  1. 利用DbgHelp.h检索所有方法&#39;一个类的符号和内存地址。基本上它在运行时从.pdb文件中检索元信息。
  2. 将用户输入与模拟方法符号与步骤1的输出进行比较,得到to-mock方法的内存地址。
  3. 利用windows api WriteProcessMemory更改to-mock方法的入口字节,类似于:__ asm {move eax,1;保留}。
  4. 让我们把关键代码放在这里。

    1. 检索方法&#39;一个类的符号和地址。以下是实施的关键思路。完整的源代码可在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. 第2步是微不足道的。它只是文本比较和处理。

    3. 如何注入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);
      }