Stubbing WinBase.h in cppunit test

385 views Asked by At

I'm writing a unit test for a class that uses named pipes. I need to stub CreateNamedPipe, ConnectNamedPipe, WriteFile, ReadFile, FlushFileBuffers, DisconnectNamedPipe, CloseHandle, and GetLastError

These are all defined in WinBase.h as dll imports.

Unfortunately WinBase.h is a gigantic file that's used everywhere, so one can't merely stub out the items you want to test...

I tried copying WinBase.h and making inline versions of the functions:

bool
ConnectNamedPipe(
    __in        HANDLE hNamedPipe,
    __inout_opt LPOVERLAPPED lpOverlapped
    )
{ return false; }

But I get a compile error for every overridden function/object pair:

3>test.obj : error LNK2005: ReadFile already defined in main.obj

Main is very minimal, but it does contain

#include <file_templates/cppunit/generic_cppunit_main.cpp>

Which is likely to include WinBase.h somewhere in it's depths...

Even if I resolve this compile error, there's a possibility that I could break cppunit in the process?

Any solutions short of abstracting out all pipe calls and stubbing the abstract instead of WinBase.h?

1

There are 1 answers

5
Sam Varshavchik On BEST ANSWER

Stubbing out via an abstract redirection is, pretty much the best way to do this, in my opinion, leaving you with as much remaining sanity as possible. It's possible to do this entirely using the preprocessor, and with no runtime overhead. Just use the following design pattern in your class:

#ifndef MY_CREATE_NAMED_PIPE
#define MY_CREATE_NAMED_PIPE CreateNamedPipe
#endif

#ifndef MY_CONNECT_NAMED_PIPE
#define MY_CONNECT_NAMED_PIPE ConnectNamedPipe
#endif

... and so on. Then, have your code invoke the system calls using their #defined aliases.

Feel free to use whatever munging convention you prefer.

Then, in your unit test module:

#define MY_CREATE_NAMED_PIPE my_create_named_pipe
#define MY_CONNECT_NAMED_PIPE my_connect_named_pipe

// And so on, then include your source module directly:

#include "source.cpp"

Your unit test module will then implement my_create_named_pipe() stubs, et al. Essentially, you will end up building a separate copy of your source module, for your unit test, that's identical in every way, except for the names of the invoked system calls.