通过 MOCK_METHOD 模拟类时,它是否需要 override 关键字?

When mocking a class via MOCK_METHOD, does it need the override keyword?

提问人:davidj361 提问时间:11/11/2023 最后编辑:davidj361 更新时间:11/11/2023 访问量:68

问:

假设我有

class Foo {
 public:
    VIRTUAL_FOR_TEST void bar(int i);
};

它被嘲笑的地方

class FooMock : public Foo {
 public:
    MOCK_METHOD(void, bar, (int), ());
};

Foo 应该只是为了单元测试而虚拟的,因为在生产代码中不需要继承它。您还需要提供关键字吗?overrideMOCK_METHOD

编辑:

如果需要,为什么可以选择输入?为什么不默认为 ?overrideoverrideMOCK_METHOD

C++ googletest googlemock

评论

2赞 StoryTeller - Unslander Monica 11/11/2023
“Foo 应该只是为了单元测试而虚拟”——所以你测试的代码版本与你实际部署的代码版本不同?这是非常不明智的——甚至可能是不道德的——只要问问大众汽车就知道了。
0赞 davidj361 11/11/2023
除了用于模拟目的的模拟类之外,Foo 没有被任何东西继承。为什么在生产中需要虚拟?我不遵循大众汽车的参考资料。
0赞 StoryTeller - Unslander Monica 11/11/2023
你是对的,这确实是一种代码气味。然而,对代码异味的正确反应是修复相关组件的设计,而不是作弊,这样我们就可以说我们“以正确的方式进行了测试”。
0赞 Eljay 11/11/2023
可能是骗子:stackoverflow.com/q/5777733/4641116
1赞 Yksisarvinen 11/11/2023
@davidj361 大众汽车的参考资料是,他们有特殊的代码,在环境保护测试下运行排放控制。通常,该功能被禁用,因此虽然它通过了测试以获准销售,但它实际上多次违反了规范。

答:

1赞 Yksisarvinen 11/11/2023 #1

override从来都不是必需的。它是在 C++11 中添加的,以帮助程序员清楚地传达意图,并通过使编译器抛出错误来捕获愚蠢的错别字,如果标记的方法实际上没有覆盖任何内容。override

MOCK_METHOD是一个扩展为常规函数声明的宏(嗯,这个函数和另一个函数是模拟体)。由于在任何情况下都不需要添加说明符,因此此处也不需要添加说明符。我曾经使用 without 作为 GMock 限制的解决方法(它无法模拟当天仅返回移动类型的函数)。overrideMOCK_METHODoverride

添加这绝对是一个好主意,因为它有助于捕获代码中的更改,而不必想知道“为什么这个模拟没有被调用”。虽然我有点同意评论者的观点,即你应该测试你执行的代码,但我也认为不应该仅仅为了测试目的而修改代码。“改变你的设计”的建议在Java中是有效的,无论如何你都必须支付函数的成本,但不一定在C++中。overridevirtual

评论

0赞 davidj361 11/13/2023
如果覆盖在 95% 的时间内被使用,为什么不默认呢?
1赞 Yksisarvinen 11/13/2023
@davidj361 默认在哪里?在语言中将其设置为默认值将是一个重大更改并且难以执行(您愿意使用说明符吗?它应该在哪里使用?如果函数与基类中的虚函数同名,它是否应该抛出错误,即使它通常是阴影而不是覆盖?仅在 GMock 中将其设置为默认值会很奇怪且不一致(没有自动应用其他函数说明符,并且为此创建说明符并不容易)。nooverridenooverride
0赞 davidj361 11/14/2023
添加覆盖绝对是一个好主意,因为它有助于捕获代码中的更改,而不必想知道“为什么这个模拟没有被调用”我不明白这部分。你说的模拟没有被叫出来是什么意思?你能举个例子吗?
1赞 Yksisarvinen 11/14/2023
比如说,你有一个 with 方法。你嘲笑它,它工作正常。但是有一天,您重构了代码并将方法更改为 ,或者将其重命名为 。使用 on mock,编译器会立即阻止您并强制更新 mock。如果没有 ,它会愉快地编译所有内容,如果您运行测试,它们将失败,因为 mock 没有更新。这个例子不是很有说服力,但这样的事情确实发生在复杂的代码中,而且它们可能很难追踪。class Foovirtual void bar();virtual void bar(int);virtual void baz();overrideoverride