HippoMocks - 用C ++模拟COM接口?

时间:2013-03-08 16:22:42

标签: c++ visual-c++ mocking hippomocks

The latest version of Hippo Mocks(在其Git存储库中)看起来已经添加了对COM接口的支持。我试过模拟一个ADO连接对象;这需要对Hippo Mocks进行一些调整才能正确构建(似乎代码的COM版本没有针对其他Hippo Mocks的更改进行更新)。我现在正在建设,但以下测试失败了:

MockRepository mocks;
auto pConn = mocks.Mock<ADONS::_Connection>();
mocks.OnCall(pConn, ADONS::_Connection::AddRef).Return(1);

ADONS::_ConnectionPtr conn = pConn;

智能指针首先做的是AddRef接口。我的模拟不应该关心引用计数,所以我添加一个只返回1的调用期望。但是,只要调用AddRef,就会抛出HippoMocks::NotImplementedException

有没有人成功模拟与Hippo Mocks的COM接口?

1 个答案:

答案 0 :(得分:2)

我有同样的问题并解决了它。 hippomocks的实际版本现在发布在github上:

https://github.com/dascandy/hippomocks

非常感谢所提供的链接,这有助于找到修复的想法。

更新,有关我的实施和添加的COM支持的详细信息。

首先我做了它,以下测试演示了

class ICom 
{
public:
    virtual ~ICom() {}
    virtual long __stdcall A(void) = 0;
    virtual long __stdcall B(int) = 0;
    virtual long __stdcall C(int, int) = 0;
    ...
};


TEST(checkStdCallBase)
{
    MockRepository mocks;

    ICom* ic = mocks.Mock<ICom>();
    mocks.ExpectCall(ic, ICom::A)
        .Return(1);

    long actual = ic->A();
    EQUALS(1, actual);
}

为了使其工作,我必须修补hippomocks.h中的几个地方,这是virtual_function_index方法中最重要的。校正可确保在接口上进行正确的地址计算。

其次,我为COM对象添加了一些常用的设置助手,为AddRef,Release和QueryInterface提供了标准行为。

测试显示如何使用它:

MIDL_INTERFACE("4745C05E-23E6-4c6d-B9F2-E483359A8B89")
COMInterface1 : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE getTObjectCount( 
        /* [out] */ unsigned long *pCount) = 0;
};

typedef GUID ESTypeID;

MIDL_INTERFACE("356D44D9-980A-4149-A586-C5CB8B191437")
COMInterface2 : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE getMappablePackages( 
        /* [out] */ long *pSize,
        /* [size_is][size_is][out] */ ESTypeID **pIdList) = 0;
};

        TEST(CheckThat_AddCommExpectations_Stubs_QueryInterface_AddRef_Release)
{
    MockRepository mocks; 
    COMInterface1* deviceMock = mocks.Mock<COMInterface1>();

    AddComExpectations(mocks, deviceMock);

    {
        CComPtr<IUnknown> pUnk = deviceMock;  
        CComQIPtr<COMInterface1> pDevice = pUnk;

        CHECK(pDevice == pUnk);

        IUnknown* p = NULL;
        pDevice->QueryInterface(__uuidof(IUnknown), (void**)&p);

        CHECK(p == deviceMock);
    }
}

TEST(CheckThat_ConnectComInterfaces_Stubs_QueryInterface_ToEachOther)
{
    MockRepository mocks; 
    COMInterface1* deviceMock = mocks.Mock<COMInterface1>();
    COMInterface2* devMappingMock = mocks.Mock<COMInterface2>();

    ConnectComInterfaces(mocks, deviceMock, devMappingMock);

    {
        //Com objects can reach each other
        CComQIPtr<COMInterface2> pDevMapping = deviceMock;

        CHECK(pDevMapping != NULL);
        CHECK(pDevMapping == devMappingMock);

        CComQIPtr<COMInterface1> pDevNavigate = devMappingMock;

        CHECK(pDevNavigate != NULL);
        CHECK(pDevNavigate == deviceMock);
    }

}

辅助方法AddComExpectations和ConnectComInterfaces在单独的头文件“comsupport.h”中提供。标题是Hippomocks的附加组件:

template <typename T>
void AddComExpectations(HM_NS MockRepository& mocks, T* m)
{
    mocks.OnCall(m, T::AddRef)
        .Return(1);
    mocks.OnCall(m, T::Release)
        .Return(1);
    mocks.OnCall(m, T::QueryInterface)
        .With(__uuidof(T), Out((void**)m))
        .Return(S_OK);

    mocks.OnCall(m, T::QueryInterface)
        .With(__uuidof(IUnknown), Out((void**)m))
        .Return(S_OK);

}

template <typename T1, typename T2>
void ConnectComInterfaces(HM_NS MockRepository& mocks, T1* m1, T2* m2)
{
    //from T1 to T2
    mocks.OnCall(m1, T1::QueryInterface)
        .With(__uuidof(T2), Out((void**)m2))
        .Return(S_OK);
    //from T2 to T1
    mocks.OnCall(m2, T2::QueryInterface)
        .With(__uuidof(T1), Out((void**)m1))
        .Return(S_OK);

    AddComExpectations(mocks, m1);
    AddComExpectations(mocks, m2);

    //no support for interface hierarchies
    //no Base IUnknown -> do it yourself if you really need that special case
}