Reputation:
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
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:
MOCK_STDCALL_FUNC(DWORD, GetCurrentProcessId);
MOCK_STDCALL_FUNC(DWORD, GetProcessIdOfThread, HANDLE);
EXPECT_MODULE_FUNC_CALL(GetCurrentProcessId).WillRepeatedly(Return(42));
ON_MODULE_FUNC_CALL(GetProcessIdOfThread, Eq(HANDLE(42))).WillByDefault(Return(1));
Upvotes: 2
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
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
Reputation: 8174
Use Deviare API hook and intercept all api calls and make your unit test.
Upvotes: 3
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
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