19

授業がある

class CSumWnd : public CBaseWnd
{

 private:
 bool MethodA()
}

MethodA()仮想化せずにモックする方法を教えてください、私はhi-perf依存性注入の概念を理解していませんでした

4

3 に答える 3

20

これは、本番コードをテンプレート化する必要があることを意味します。あなたの例を使用して:

CSumWindクラス定義:

class CSumWnd : public CBaseWnd
{

 private:
 bool MethodA()
};

モックCSumWndクラス定義:

class MockCSumWnd : public CBaseWnd
{

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

モッククラスでテストする必要がある本番クラスCSumWindCSumWindこれで、本番コードでMockCSumWndクラスを使用し、テストでクラスを使用するようにテンプレート化されます。

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

private:
  CSumWndClass sumWnd;
};

生産中のインスタンスTestedClass化:

TestedClass <CSumWnd> obj;

TestedClassテスト実行可能ファイル内のオブジェクトのインスタンス化:

TestedClass <MockCSumWnd> testObj;
于 2011-04-25T11:40:04.027 に答える
3

既存のコードを変更したくない場合は、私が取り組んでいるVC ++の特定のソリューションを次に示します(https://github.com/mazong1123/injectorpp)。簡単な手順は次のとおりです。

  1. DbgHelp.hを利用して、クラスのすべてのメソッドのシンボルとメモリアドレスを取得します。基本的に、実行時に.pdbファイルからメタ情報を取得します。
  2. ユーザー入力のto-mockメソッドシンボルをステップ1の出力と比較し、to-mockメソッドのメモリアドレスを取得します。
  3. windows api WriteProcessMemoryを利用して、to-mockメソッドのエントリバイトを変更します。これは、次のようなものです。__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. メソッドの動作を変更するためにマジックアセンブリを注入する方法:(完全なソースコードは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);
    }
    
于 2016-05-28T17:00:33.650 に答える
2

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());
}
于 2014-09-28T04:38:17.597 に答える