chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Answers. Here you can ask and receive answers from other community members. And if you liked or disliked an answer or thread: react with an up- or downvote Enjoy!

Using isolator++ for mocking COM objects

+1 vote
We have a Win32 application which extensively utilizes COM objects. We decided to put our production code to unit tests, but the task turned out to be complicated, because these tests require user interaction and makes other undesirable calls to operating system functionality (via COM).

Can we use isolator++ for mocking COM objects? Can you provide any code sample?

Thanks!
asked Jun 5 by KevinGard (640 points)

1 Answer

0 votes
 
Best answer

Hi Kevin,

Yes, Isolator++ supports mocking any of C++ classes, and COM objects as well.

Instantiation of COM objects is usually done by calling \"CoCreateInstance\", so you can mock this function to return fake classes instead of real ones.

Here is an example of applying such technique to mock IFileOpenDialog object\'s functionality:

#include <gtest\gtest.h>

#include "Isolator.h"


#include <windows.h>

#include <shobjidl.h> 



class COMEnv : public ::testing::Environment 

{

virtual void SetUp() override

{

auto hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

ASSERT_TRUE(SUCCEEDED(hr));

}

};


class COMFaking : public ::testing::Test

{

public:


virtual void TearDown() override

{

ISOLATOR_CLEANUP();

}


static HRESULT STDAPICALLTYPE FakeCoCreateInstance(

_In_ REFCLSID rclsid,

_In_opt_ LPUNKNOWN pUnkOuter,

_In_ DWORD dwClsContext,

_In_ REFIID riid,

LPVOID * ppv)

{

if( rclsid == CLSID_FileOpenDialog)

{

//Create fake instance

auto od = FAKE<IFileOpenDialog>();

//Mock Show method to return S_OK and do nothing

WHEN_CALLED(od->Show(_)).Return(S_OK);

//Make GetResult method return fake IShellItem

auto si = FAKE<IShellItem>();

WHEN_CALLED(si->GetDisplayName(ANY_VAL(SIGDN),RET(BY_REF(_fake_path)))).Return(S_OK);

WHEN_CALLED(od->GetResult(RET(BY_REF(si)))).Return(S_OK);

*ppv = od;

//Check

auto rc = od->Close(0);

return S_OK;

}

return S_FALSE;

}


static PWSTR _fake_path;

};


PWSTR COMFaking::_fake_path = L"C:\\myfile.txt";


TEST_F(COMFaking, UsingRET)

{

FAKE_GLOBAL(CoCreateInstance);


typedef LPVOID* LPPVOID;

WHEN_CALLED(

CoCreateInstance(

ANY_REF(CLSID),

_,

_,

ANY_REF(IID),

ANY_REF(LPPVOID) ) ).DoStaticOrGlobalInstead(COMFaking::FakeCoCreateInstance, nullptr);



IFileOpenDialog *pFileOpen = nullptr; 

//Create file open dialog

auto hr = ::CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));

ASSERT_TRUE(SUCCEEDED(hr));

//Show it (fake behavior)

hr = pFileOpen->Show(nullptr);

ASSERT_TRUE(SUCCEEDED(hr));

//Get item (fake object)

IShellItem *pItem = nullptr;

    hr = pFileOpen->GetResult(&pItem);

//Validate

ASSERT_TRUE(pItem != nullptr);

ASSERT_TRUE(SUCCEEDED(hr));

PWSTR pszPath = nullptr;

    hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);

ASSERT_TRUE(SUCCEEDED(hr));

//Check if the value was faked

ASSERT_STREQ(pszPath, _fake_path);

}


int main(int argc, char** argv)

{

::testing::InitGoogleTest(&argc, argv);

::testing::AddGlobalTestEnvironment(new COMEnv());

return RUN_ALL_TESTS();

}

answered Jun 5 by SapirTypemock (2,120 points)
selected Jun 10 by KevinGard
I understand, thank you!
...