Is this an idiomatic way to pass mocks into objects?

Posted by Billy ONeal on Stack Overflow See other posts from Stack Overflow or by Billy ONeal
Published on 2010-05-26T18:22:43Z Indexed on 2010/05/26 18:51 UTC
Read the original article Hit count: 285

Filed under:
|

I'm a bit confused about passing in this mock class into an implementation class. It feels wrong to have all this explicitly managed memory flying around. I'd just pass the class by value but that runs into the slicing problem.

Am I missing something here?

Implementation:

namespace detail
{
    struct FileApi
    {
        virtual HANDLE CreateFileW(
              __in      LPCWSTR lpFileName,
              __in      DWORD dwDesiredAccess,
              __in      DWORD dwShareMode,
              __in_opt  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
              __in      DWORD dwCreationDisposition,
              __in      DWORD dwFlagsAndAttributes,
              __in_opt  HANDLE hTemplateFile
            )
        {
            return ::CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
        }
        virtual void CloseHandle(HANDLE handleToClose)
        {
            ::CloseHandle(handleToClose);
        }
    };
}

class File : boost::noncopyable
{
    HANDLE hWin32;
    boost::scoped_ptr<detail::FileApi> fileApi;
public:
    File(
    __in      LPCWSTR lpFileName,
    __in      DWORD dwDesiredAccess,
    __in      DWORD dwShareMode,
    __in_opt  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    __in      DWORD dwCreationDisposition,
    __in      DWORD dwFlagsAndAttributes,
    __in_opt  HANDLE hTemplateFile,
    __in      detail::FileApi * method = new detail::FileApi()
    )
    {
        fileApi.reset(method);
        hWin32 = fileApi->CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
    }
};  namespace detail
{
    struct FileApi
    {
        virtual HANDLE CreateFileW(
              __in      LPCWSTR lpFileName,
              __in      DWORD dwDesiredAccess,
              __in      DWORD dwShareMode,
              __in_opt  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
              __in      DWORD dwCreationDisposition,
              __in      DWORD dwFlagsAndAttributes,
              __in_opt  HANDLE hTemplateFile
            )
        {
            return ::CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
        }
        virtual void CloseHandle(HANDLE handleToClose)
        {
            ::CloseHandle(handleToClose);
        }
    };
}

class File : boost::noncopyable
{
    HANDLE hWin32;
    boost::scoped_ptr<detail::FileApi> fileApi;
public:
    File(
    __in      LPCWSTR lpFileName,
    __in      DWORD dwDesiredAccess,
    __in      DWORD dwShareMode,
    __in_opt  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    __in      DWORD dwCreationDisposition,
    __in      DWORD dwFlagsAndAttributes,
    __in_opt  HANDLE hTemplateFile,
    __in      detail::FileApi * method = new detail::FileApi()
    )
    {
        fileApi.reset(method);
        hWin32 = fileApi->CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
    }
    ~File()
    {
        fileApi->CloseHandle(hWin32);
    }
};

Tests:

namespace detail {
    struct MockFileApi : public FileApi
    {
        MOCK_METHOD7(CreateFileW, HANDLE(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE));
        MOCK_METHOD1(CloseHandle, void(HANDLE));
    };
}

using namespace detail;
using namespace testing;

TEST(Test_File, OpenPassesArguments)
{
    MockFileApi * api = new MockFileApi;
    EXPECT_CALL(*api, CreateFileW(Eq(L"BozoFile"), Eq(56), Eq(72), Eq(reinterpret_cast<LPSECURITY_ATTRIBUTES>(67)), Eq(98), Eq(102), Eq(reinterpret_cast<HANDLE>(98))))
        .Times(1).WillOnce(Return(reinterpret_cast<HANDLE>(42)));
    File test(L"BozoFile", 56, 72, reinterpret_cast<LPSECURITY_ATTRIBUTES>(67), 98, 102, reinterpret_cast<HANDLE>(98), api);
}

© Stack Overflow or respective owner

Related posts about c++

Related posts about TDD