我目前使用的产品是用C ++编写的Windows服务,并且所有新功能都将为其编写单元测试。但是这会产生一个有趣的问题(至少对我来说)我们会针对各种事情做很多Win32调用并相应地运行,所以为了完成单元测试,测试各种输出会很好,而不仅仅是当前系统状态。
我的问题是模拟Win32调用结果的最佳方法是什么?我考虑过两种不同的方法:
1)将所有使用的Win32调用放入函数指针并将它们传递给使用它们的函数或类(取决于它们被击中的次数)并使用它来获得模拟结果。
2)到处都有很多#ifdef UNITTEST
,如果它正在调用我自己的特殊方法,或者如果没有,则调用正常的方法。
我完全偏离这里,还是错过了一个基本的知识?
答案 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
,其中包含RegOpenKey
,RegQueryValueEx
,RegNotifyChange
以及我正在使用的其他几个。在构造函数中创建了一个简单调用真实函数的默认函数,但我还有一个构造函数,它接受了接口,因此我可以模拟狡猾的值等。
(不知道回答我自己的问题是不是礼仪不好)
答案 4 :(得分:-1)
如果可能,最好在不修改Win32调用的情况下使事件发生。
例如,不是让你自己的CreateFile
因文件正在使用而失败,而是专门用另一个程序打开文件(你从单元测试中调用)然后运行单元测试。
如果你必须模拟一些win32调用,那么最好围绕你想要制作的Win32调用集创建一个包装器库。那么你不会损害主逻辑的代码读写能力。