Макет не виртуального метода C++ (gmock)
у меня класс
class CSumWnd : public CBaseWnd
{
private:
bool MethodA()
}
пожалуйста, вы можете помочь как глумятся MethodA()
без создания виртуального,
Я не понимал понятия инъекция зависимости hi-perf
3 ответов
это означает, что вам придется templatize рабочий код. Используя Ваш пример:
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
in производство:
TestedClass <CSumWnd> obj;
экземпляров TestedClass
объект в тестовом исполняемом файле:
TestedClass <MockCSumWnd> testObj;
попробовать 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());
}
Если вы не хотите изменять существующий код, вот конкретное решение для VC++, над которым я работаю (https://github.com/mazong1123/injectorpp). Короткие шаги:
- Использовать DbgHelp.h для извлечения символов всех методов и адресов памяти класса. В основном он извлекает мета-информацию .pdb-файл во время выполнения.
- сравните пользовательский ввод с символом метода-mock с выходом шага 1, получите память метода to-mock адрес.
- используйте Windows api WriteProcessMemory для изменения байтов ввода метода to-mock, что-то вроде: __asm {move eax, 1; ret}.
давайте положим код ключа здесь.
-
получить символы и адреса методов класса. Ниже приводится ключевая идея реализации. Полный исходный код доступен на 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-тривал. Это всего лишь сравнение и обработка текста.
-
Как ввести 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); }