How to unit test with functions loaded from win32 api?
-
Hello, I am writing unit tests for some functions that use calls to functions derived form win32 api and securitybaseapi, specifically LogonUserW and ImpersonateUser. I am not sure how to stub these functions out to get the output that I desire. I have looked at Gmock and Deviare but is there a better approach for stubbing out these calls in my project?
-
Hi and welcome to devnet,
From the top of my head, you should have an abstraction that encapsulate these function so you can provide a mock object based on this abstraction for the tests and otherwise use the API based implementation when running the application.
-
If abstraction over the API is not an option, you might consider using the gmock-win32 library.
-
Hi @dk10124, as @SGaist suggested, some form of mocke-dependency injection would be ideal. For example, you could pass a function pointer to your function, where the function pointer defaults to
&LogonUserW
normally, but your tests can pass their own mock function equivalent (ie with the same signature asLogonUserW()
) to the function being tested.Another option, which I don't necessarily recommend (it definitely has some disadvantages) is to use a macro. It's not something I would normally suggest, but actually kind of fits with win32 conventions.
So first, a small step back: personally, I wouldn't call
LogonUserW()
directly. Although its less relevant today, for portability (and thus as you'll often within Qt's internal code), I would use theLogonUser()
macro instead. The win32 convention (love it or hate it), is to provide two versions of most win32 functions - one with anA
suffix for 8-bit "ASCII" char strings, and one with aW
suffix for 16-bit "Wide" (aka UNICODE, aka UCS-2) char strings. So, for example, in thewinbase.h
header, you'll see:#ifdef UNICODE #define LogonUser LogonUserW #else #define LogonUser LogonUserA #endif
So if, for example, you're code was to use
LogonUser()
, then you'd actually be calling a macro, and that macro could be conditionally redefined when unit-testing. Something like:#include <all the things> #ifdef QT_TESTLIB_LIB #undef LogonUser #define LogonUser LogonUserMock #endif // your code that uses LogonUser() ...
One major disadvantage is that approach requires the code-under-test to be compiled and linked as part of the test project. That is, you can't link to the "release" binaries (
*.o
or*.lib
/*.dll
) since the macro replacement only happens at compile time (unless the code is header-only). Still, I present it as just another option, that might suite depending on your specific needs.Cheers.
-
-
@Paul-Colby is hinting at something good. If you want to be able to cleanly test things, you should consider making a library with all your widgets and business logic and your application will be mainly a
main.cpp
file using that library. This will allow you to build a test suite for your library in a simpler fashion.