1

最新版本的 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就会抛出 a。

有没有人成功地用 Hippo Mocks 模拟 COM 接口?

4

1 回答 1

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
}
于 2015-11-10T09:26:35.513 回答