Макет невиртуального метода C ++ (gmock)

у меня урок

class CSumWnd : public CBaseWnd
{

 private:
 bool MethodA()
}

Не могли бы вы помочь, как имитировать MethodA(), не создавая виртуальный, я не понял концепцию внедрение высокопроизводительных зависимостей


person Sasi    schedule 25.04.2011    source источник
comment
Ваша ссылка мертва - не могли бы вы ее обновить? Я не могу найти ту же страницу, возможно, этого достаточно?   -  person Chris_128    schedule 13.02.2020


Ответы (3)


Это означает, что вам придется шаблонизировать свой производственный код. Используя ваш пример:

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;
person beduin    schedule 25.04.2011
comment
Чтобы ваш «производственный» код оставался чистым, я считаю полезным сделать следующее: шаблон ‹класс CSumWndClass› класс TestedClassTemplate {...}, а затем выполнить typedef TestedClassTemplate ‹CSumWndClass› TestedClass; - person smehmood; 28.04.2011
comment
См. stackoverflow.com/q/1127918/49972 для получения информации о последствиях выполнения того, что вы предлагаете. - person Tobias Furuholm; 27.05.2011
comment
Я столкнулся с проблемой в MOCK_METHOD(MethodA, bool()); stackoverflow.com/questions/46542373/ Я получаю сообщение об ошибке, указанной в вопросе выше - person CMouse; 03.10.2017
comment
MOCK_METHOD следует заменить параметрами MOCK_METHOD0 // 0. Должно быть; также после bool MethodA (). К сожалению, идея мне до сих пор не ясна ... - person Artem Bobritsky; 10.05.2019

Если вы не хотите изменять существующий код, вот конкретное решение для VC ++, над которым я работаю (https://github.com/mazong1123/injectorpp). Краткие шаги:

  1. Используйте DbgHelp.h для получения всех символов методов и адресов памяти класса. В основном он извлекает метаинформацию из файла .pdb во время выполнения.
  2. Сравните ввод пользователя с символом имитационного метода с выходными данными шага 1 и получите адрес памяти имитационного метода.
  3. Используйте Windows api WriteProcessMemory для изменения байтов записи метода имитации, который выглядит примерно так: __asm ​​{move eax, 1; ret}.

Поместим сюда ключевой код.

  1. Получить символы и адреса методов класса. Ниже представлена ​​ключевая идея реализации. Полный исходный код доступен по адресу 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. Как внедрить волшебный 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);
    }
    
person Jim Ma    schedule 28.05.2016
comment
Выглядит интересно. Я бы хотел увидеть что-то подобное для GCC / Clang. - person hedayat; 02.09.2017
comment
@hedayat Я планирую это сделать. Недавно я почти закончил часть x86 Windows. Оставайтесь с нами. - person Jim Ma; 01.10.2017

Попробуйте 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());
}
person Louix    schedule 28.09.2014
comment
Эта вторая ссылка для меня указывает на вход в OneDrive. Кроме того, вместо того, чтобы использовать здесь как описание, было бы лучше добавить что-то более информативное, чтобы документ можно было найти, если ссылка умрет в будущем. - person PeterJ; 28.09.2014
comment
У меня недостаточно репутации, чтобы добавить более двух ссылок в один ответ, обновите ссылку здесь, больше не нужно входить в систему. Полную документацию можно найти на гитхабе. - person Louix; 28.09.2014
comment
похоже, что он не может скомпилироваться с текущим gmock - person Artem Bobritsky; 10.05.2019
comment
@Louix Мне кажется, что вы автор CppFreeMock. Вы должны сообщить об этом в ответе. - person Jörn Schellhaas; 19.01.2021