【问题标题】:Mocking and Win32 API Calls模拟和 Win32 API 调用
【发布时间】:2009-07-22 14:55:18
【问题描述】:

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

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

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

2) 到处都有很多#ifdef UNITTEST,如果它正在调用我自己的特殊方法,或者如果没有调用普通方法。

我是不是完全偏离了基础,还是缺少基本知识?

【问题讨论】:

  • 如果您需要参数来修改 UnitTestMessageBox 的行为怎么办? #ifdef UNITTEST #undef MessageBox #define MessageBox UnitTestMessageBox #endif

标签: c unit-testing winapi mocking


【解决方案1】:

关于 (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

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

【讨论】:

  • 这是我的想法。我会避免更改您的函数签名以进行单元测试。
【解决方案2】:

我建议将 API 调用封装到精心设计的接口中。然后,您可以使用模拟对象或测试替身来测试您的业务逻辑。您不需要测试 Windows API 本身,因为这已经由数百万个正在运行的 Windows 应用程序完成。

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

【讨论】:

    【解决方案3】:

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

    例如,我有一个名为IRegistryOperations,其中包含RegOpenKeyRegQueryValueExRegNotifyChange 和我正在使用的其他几个。在构造函数中创建了一个简单调用真实函数的默认构造函数,但我也有一个使用接口的构造函数,因此我可以模拟不可靠的值等。

    (虽然不知道回答我自己的问题是否是不好的礼仪)

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        例如,不要创建自己的CreateFile,因为文件正在使用中而失败,而是使用另一个程序(您从单元测试中调用)专门打开该文件,然后运行单元测试。

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

        【讨论】:

          猜你喜欢
          • 2010-11-16
          • 1970-01-01
          • 2021-05-31
          • 2021-12-30
          • 2017-01-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多