模拟和Win32 API调用

时间:2009-07-22 14:55:19

标签: c unit-testing winapi mocking

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

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

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

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

我完全偏离这里,还是错过了一个基本的知识?

5 个答案:

答案 0 :(得分: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

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

答案 1 :(得分:4)

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

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

答案 2 :(得分:2)

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

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:-1)

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

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

如果你必须模拟一些win32调用,那么最好围绕你想要制作的Win32调用集创建一个包装器库。那么你不会损害主逻辑的代码读写能力。