模拟和 Win32 API 调用

问题描述 投票:0回答:6

我目前使用的产品是用 C++ 编写的 Windows 服务,未来所有新功能都将为其编写单元测试。但这产生了一个有趣的问题(至少对我而言)我们对各种事物进行了大量 Win32 调用并相应地进行操作,因此为了完成单元测试,最好测试各种输出,而不仅仅是当前系统状态。

我的问题是模拟 Win32 调用结果的最佳方法是什么?我想过两种不同的方法:

1) 将所有使用到的Win32调用都放入函数指针中,并传递给使用它们的函数或类(取决于它们被命中的次数),并使用它来获得模拟结果。

2)到处都有很多

#ifdef UNITTEST
,如果它正在调用我自己的特殊方法,或者如果没有调用普通方法。

我在这里完全偏离了基地,还是缺少基本知识?

c unit-testing winapi mocking
6个回答
9
投票

关于 (2),大多数采用字符串参数的 Win32 函数已经将它们的通用形式定义为宏,例如来自 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

你当然可以在你的项目中添加一个头文件来重新定义你想要模拟的 API 函数:

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

通过重新定义名称,您可以避免在整个源代码中散布大量条件编译。


6
投票

最后,我实际上采用了更多 C#-ish 方法并创建了接口,使我能够存根我想使用的 Win32 调用。

例如,我有一个名为

IRegistryOperations
的程序,其中包含
RegOpenKey
RegQueryValueEx
RegNotifyChange
和我正在使用的其他几个程序。在构造函数中创建了一个简单地调用真实函数的默认函数,但我也有一个采用接口的构造函数,因此我可以模拟不可靠的值等。

(不确定回答我自己的问题是否不礼貌)


5
投票

我建议将 API 调用封装到结构良好的接口中。然后,您可以使用模拟对象或测试替身来测试您的业务逻辑。您不需要测试 Windows API 本身,因为数百万工作的 Windows 应用程序已经完成了这项工作。

如果您不开发硬件,则单元测试不应涉及硬件访问。这只是关于测试您的逻辑代码。


3
投票

使用 Deviare API 挂钩并拦截所有 api 调用并进行单元测试。


0
投票

您可以尝试用于 win32 API 模拟的谷歌测试 GMock lib 扩展:https://github.com/smalti/gmock-win32


-1
投票

如果可能,最好在不修改 Win32 调用的情况下使事件发生。

例如,不要让自己的

CreateFile
因文件正在使用而失败,而是用另一个程序(您从单元测试调用)专门打开文件,然后运行单元测试。

如果你必须模拟一些 win32 调用,那么最好围绕你想要进行的 Win32 调用集创建一个包装器库。那么你就不会损害主要逻辑的代码素养。

© www.soinside.com 2019 - 2024. All rights reserved.