user1333
user1333

Reputation:

Mocking and Win32 API Calls

The current product I work on is a Windows Service written in C++ and going forward all new functionality will have unit tests written for it. But this creates an interesting problem (for me at least) we do a lot of Win32 calls for various things and behave accordingly, so for the unit tests to be complete it would be nice to test a variety of outputs, not just the current system state.

My question is what is the best way to mock the results of the Win32 calls? I have thought about two different methods:

1) Put all the Win32 calls used into function pointers and pass them into the functions or classes (depending on how many times they are hit) that use them and use this to get mock results.

2) Have lots of #ifdef UNITTEST everywhere and if it is calling my own special methods or have the normal ones called if not.

Am I completely off base here, or missing a fundamental piece of knowledge?

Upvotes: 9

Views: 5689

Answers (6)

Smalti
Smalti

Reputation: 507

You can mimic or simulate the functions of the system by replacing them with something else. One way to do this is to use libraries like Detours MS or mhook lib. Another method is to patch the import table and substitute the win32 functions, to see an example of how this can be done, check out the gmock-win32 library that I wrote. You can use it by following the usage instructions provided:

  1. Create Win32 function mocks:
MOCK_STDCALL_FUNC(DWORD, GetCurrentProcessId);
MOCK_STDCALL_FUNC(DWORD, GetProcessIdOfThread, HANDLE);
  1. Setup expectations via EXPECT_MODULE_FUNC_CALL / ON_MODULE_FUNC_CALL:
EXPECT_MODULE_FUNC_CALL(GetCurrentProcessId).WillRepeatedly(Return(42));
ON_MODULE_FUNC_CALL(GetProcessIdOfThread, Eq(HANDLE(42))).WillByDefault(Return(1));

Upvotes: 2

user1333
user1333

Reputation:

In the end I actually took more a C#-ish approach and created interfaces that would allow me to stub out the Win32 calls I wanted to use.

For example I had one called IRegistryOperations that contained RegOpenKey, RegQueryValueEx, RegNotifyChange and several others I was using. A default one that simply calls into the real function was created in the constructor but I also had a constructor that took the interface so I could simulate dodgy values, etc.

(Not sure if it's bad etiquette to answer my own question though)

Upvotes: 6

frast
frast

Reputation: 2740

I would recommend to encapsulate the API calls into well factored interfaces. Then you can test your business logic by using mock objects or test doubles. You do not need to test the Windows API itself because this is already done by millions of working Windows applications.

A unit test should never involve hardware access if you do not develop hardware. It is just about testing your logic code.

Upvotes: 5

lsalamon
lsalamon

Reputation: 8174

Use Deviare API hook and intercept all api calls and make your unit test.

Upvotes: 3

Matthew Xavier
Matthew Xavier

Reputation: 2128

With respect to (2), most Win32 functions which take string parameters already have their common form defined as a macro, e.g. from WinUser.h:

WINUSERAPI
int
WINAPI
MessageBoxA(
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType);
WINUSERAPI
int
WINAPI
MessageBoxW(
    __in_opt HWND hWnd,
    __in_opt LPCWSTR lpText,
    __in_opt LPCWSTR lpCaption,
    __in UINT uType);
#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif // !UNICODE

You could certainly add a header to your project which redefines the API functions you want to simulate:

#ifdef UNITTEST
#undef MessageBox
#define MessageBox UnitTestMessageBox
#endif

By redefining the name, you can avoid scattering lots of conditional compilation throughout your source code.

Upvotes: 9

Brian R. Bondy
Brian R. Bondy

Reputation: 347436

When possible, it would be better to make the events happen while not modifying the Win32 calls.

For example instead of making your own CreateFile that will fail because a file is in use, instead exclusively open the file with another program (that you call from your unit test) then run the unit test.

If you must mock some win32 call though, then it would probably be best to create a wrapper library around the sets of Win32 calls you want to make. Then you won't harm the code literacy of the main logic.

Upvotes: -1

Related Questions