Muh*_*san 11 c++ tdd unit-testing googlemock
我陷入了一个问题,似乎无法找到解决方案.
我正在使用VS2005 SP1来编译代码.
我有一个全局功能:
A* foo();
Run Code Online (Sandbox Code Playgroud)
我有一个模拟课
class MockA : public A {
public:
MOCK_METHOD0 (bar, bool());
...
};
Run Code Online (Sandbox Code Playgroud)
在消息来源中,它是这样访问:foo()->bar().我无法找到模仿这种行为的方法.我无法改变消息来源,因此谷歌模拟烹饪书中的解决方案是不可能的.
任何有关正确方向的帮助或指示都将受到高度赞赏.:)
πάν*_*ῥεῖ 16
不可能,如果不更改源代码,或者将自己的版本foo()与可执行代码链接在一起.
从GoogleMock的常见问题,它说
我的代码调用静态/全局函数.我可以嘲笑它吗?
你可以,但你需要做一些改变.
通常,如果您发现自己需要模拟静态函数,则表明您的模块耦合得太紧(并且灵活性较低,可重用性较低,可测试性较差等).你可能最好定义一个小接口并通过该接口调用该函数,然后可以很容易地模拟它.这最初是一项工作,但通常会很快收回成本.
这篇Google测试博客文章非常出色.看看这个.
也来自食谱
嘲弄自由功能
可以使用Google Mock来模拟自由函数(即C风格函数或静态方法).您只需要重写代码以使用接口(抽象类).
不是直接调用自由函数(比如OpenFile),而是为它引入一个接口,并有一个调用自由函数的具体子类:
Run Code Online (Sandbox Code Playgroud)class FileInterface { public: ... virtual bool Open(const char* path, const char* mode) = 0; }; class File : public FileInterface { public: ... virtual bool Open(const char* path, const char* mode) { return OpenFile(path, mode); } };您的代码应与FileInterface对话以打开文件.现在很容易模拟出这个功能.
这可能看起来很麻烦,但实际上你经常有多个相关的函数可以放在同一个接口中,所以每个函数的语法开销会低很多.
如果您担心虚拟功能带来的性能开销,并且分析确认您的问题,则可以将其与模拟非虚方法的配方相结合.
正如您在评论中提到的那样,您实际上提供了自己的版本foo(),您可以轻松解决此问题,其中包含另一个模拟类的全局实例:
struct IFoo {
virtual A* foo() = 0;
virtual ~IFoo() {}
};
struct FooMock : public IFoo {
FooMock() {}
virtual ~FooMock() {}
MOCK_METHOD0(foo, A*());
};
FooMock fooMock;
// Your foo() implementation
A* foo() {
return fooMock.foo();
}
TEST(...) {
EXPECT_CALL(fooMock,foo())
.Times(1)
.WillOnceReturn(new MockA());
// ...
}
Run Code Online (Sandbox Code Playgroud)
在每个测试用例运行后,不要忘记清除所有呼叫期望.
有 2 个选项:
如果您坚持使用 gmock,apriorit 有一个用于全局模拟的“扩展”: https: //github.com/apriorit/gmock-global
但它相当有限——或者至少我无法在 5 分钟内弄清楚如何对模拟调用产生副作用。
如果您愿意从 gmock 切换过来,那么 hippomocks 有一种非常简洁的方式可以满足您的需求。
下面是一个模拟 fopen、fclose 和 fgets 的示例,用于测试使用 cstdio 从文件读取的成员函数(流效率非常低):
TEST_CASE("Multi entry") {
std::vector<std::string> files{"Hello.mp3", "World.mp3"};
size_t entry_idx = 0;
MockRepository mocks;
mocks.OnCallFunc(fopen).Return(reinterpret_cast<FILE *>(1));
mocks.OnCallFunc(fgets).Do(
[&](char * buf, int n, FILE * f)->char *{
if (entry_idx < files.size())
{
strcpy(buf, files[entry_idx++].c_str());
return buf;
}
else
return 0;
}
);
mocks.OnCallFunc(fclose).Return(0);
FileExplorer file_explorer;
for (const auto &entry: files)
REQUIRE_THAT(file_explorer.next_file_name(), Equals(entry.c_str()));
REQUIRE_THAT(file_explorer.next_file_name(), Equals(""));
}
Run Code Online (Sandbox Code Playgroud)
被测试的函数如下所示:
string FileExplorer::next_file_name() {
char entry[255];
if (fgets((char *)entry, 255, _sorted_entries_in_dir) == NULL)
return string();
_current_idx++;
if (_current_idx == _line_offsets.size())
_line_offsets.push_back(static_cast<unsigned>(char_traits<char>::length(entry)) + _line_offsets.back());
return string(entry);
}
Run Code Online (Sandbox Code Playgroud)
我在这里使用 catch2 作为测试框架,但我认为 hippomocks 也可以与 Google 的测试框架一起使用(顺便说一句,我推荐 catch2,非常容易使用)。
| 归档时间: |
|
| 查看次数: |
21007 次 |
| 最近记录: |