I am working on a legacy project that makes massive use of ATL COM objects. The task is to extend the unit testing (googletest) by the capability of mocking COM objects, or the smart pointers accessing them. To illustrate, I created a small example project with a single ATL simple object, which only exports the method methodB (part of idl file):
object,
uuid(070a4996-d9cf-4434-a823-3ea9043de394),
dual,
nonextensible,
pointer_default(unique)
]
interface IMyATLObj : IDispatch
{
[id(1)] HRESULT methodB([in] SHORT in, [out, retval] SHORT *out);
};
The objects are accessed using smart pointers of base type _com_ptr_t, such as in this example:
#include <comdef.h>
#include ".../ATLExample_i.h"
_COM_SMARTPTR_TYPEDEF(IMyATLObj, __uuidof(IMyATLObj));
IMyATLObjPtr create() {
IMyATLObjPtr objPtr;
objPtr.CreateInstance(__uuidof(MyATLObj));
return objPtr;
}
void use(IMyATLObjPtr objPtr) {
short val = 0;
objPtr->methodB(1, &val);
std::cout << val << std::endl;
}
Now the question is how I can test the function use(...) without actually creating a COM object. Of course I can create a wrapper class as a facade to all COM interactions that I can mock as usual, e.g.:
class MyObjFacade {
public:
MyObjFacade() {
objPtr.CreateInstance(__uuidof(MyATLObj));
}
virtual short methodB(short in) {
short val;
if (objPtr->methodB(in, &val) == S_OK)
return val;
else
throw;
}
IMyATLObjPtr objPtr;
};
class MYObjMock : public MyObjFacade {
public:
MOCK_METHOD1(methodB, short(short in));
};
void use(MyObjFacade *objPtr) {
short val = 0;
val = objPtr->methodB(1);
std::cout << val << std::endl << std::flush;
}
TEST_F(COMMockTest, Test1) {
MYObjMock mock;
EXPECT_CALL(mock, methodB(_)).WillOnce(Return(43));
use(&mock);
}
But that would obviously leave me with lots of boiler plate code and (possibly) unnessessary changes - this solution would probably not be well adopted. I am looking for an elegant solution that, for example, either introduces a mock object into IMyATLObjPtr mocks the pointer object itself. However, I don't really know where to start because all the available interfaces are generated by ATL and are not easily accessible.
Any ideas?