我在 C++ 中对一个类进行单元测试,一些公共方法称为私有方法。我知道约定是测试公共接口,但类的功能取决于这些私有方法如何依次调用其他类及其方法。这类似于公共接口,无论私有函数发生什么,它仍然符合 API。
在大多数情况下,我已经能够模拟在私有函数中调用的类来测试 API,但在少数情况下,我遇到了引用标准库的地方并且没有设法模拟它。模拟标准库类等有什么技巧吗?还是我应该跳过它们?
- 我也无法更改源或使用模拟库。
我在 C++ 中对一个类进行单元测试,一些公共方法称为私有方法。我知道约定是测试公共接口,但类的功能取决于这些私有方法如何依次调用其他类及其方法。这类似于公共接口,无论私有函数发生什么,它仍然符合 API。
在大多数情况下,我已经能够模拟在私有函数中调用的类来测试 API,但在少数情况下,我遇到了引用标准库的地方并且没有设法模拟它。模拟标准库类等有什么技巧吗?还是我应该跳过它们?
- 我也无法更改源或使用模拟库。
如果您真的希望模拟标准库,那么最简单(可能唯一)的方法是正确检测您的代码。也就是说,std
您必须使用中间名称,而不是直接使用标头和命名空间。
因此,发明一个命名空间,将其命名为mstd
. 在您的模拟模式下,这将是您的模拟命名空间。在非模拟模式下,这将只是std
.
对于头文件,您必须避免直接包含标准头文件,而是使用模拟层。因此,<map>
您可以不包括在内,而是包括<mk-map>
. 然后,此头文件将在标准库和您的版本之间做出决定。或许是这样的:
#ifdef MOCK_MODE
#include "mock/map.hpp"
#else
#include <map>
#endif
您可以交替地为您的编译器提供不同的包含路径,该路径位于标准库之前。但是,由于无论如何您都必须为命名空间命名,您仍然必须修改所有代码——因此包含这些特殊标头同样容易。
这是我能看到这个工作的唯一方法。请注意,使用 LD_PRELOAD 或任何库技术都不起作用:C++ 标准库由许多模板类和内联函数组成。您需要在编译时立即替换它们。
如果您尝试对类的私有方法进行一些白盒测试,也许您的编译器会让您绕过访问控制?GCC 至少允许-fno-access-control
,我在白盒单元测试和数据结构自省(即unordered_{set,map}
.
如果您真的想狡猾,跳过访问控制还可以让您直接在其他调用之间使用成员变量。
为此,我建议您使用Typemock Isolator++ API,它允许在不重新定义的情况下模拟全局方法。看,这多么容易:
FAKE_GLOBAL(fopen);
WHEN_CALLED(fopen(0,0)).Return(_anotherFile);
而且您甚至不需要更改源代码。
真的有必要制作标准库的模型吗?当然,标准库函数可能存在错误,但您的模型可能比实际更可能存在错误。
我会说按原样使用它们。如果您追踪到标准库的测试失败,那么您就发现了标准库错误。而且,至少在短期内,您可能必须找到解决此类错误的方法。