Gmock - InSequence vs RetiresOnSaturation



我不理解下面的gmock示例:

{
InSequence s;
for (int i = 1; i <= n; i++) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i))
.RetiresOnSaturation();
}
}

当我删除.RRetiresOnSaturation()时,上面的代码以相同的方式工作-GetX返回10、20等等。当我们也使用InSequence对象时,使用.RRetires OnSaturation的原因是什么?你能解释一下吗?

在给定的确切示例中,RetiresOnSaturation()不会更改任何内容。一旦序列中的最终期望饱和,该期望保持活跃但饱和。进一步调用将导致测试失败。

RetiresOnSaturation()通常用于叠加期望值。例如:

class Turtle {
public:
virtual int GetX() = 0;
};
class MockTurtle : public Turtle {
public:
MOCK_METHOD0(GetX, int());
};
TEST(GmockStackoverflow, QuestionA)
{
MockTurtle turtle;
// General expectation - Perhaps set on the fixture class?
EXPECT_CALL(turtle, GetX()).WillOnce(Return(0));
// Extra expectation
EXPECT_CALL(turtle, GetX()).WillOnce(Return(10)).RetiresOnSaturation();
turtle.GetX();
turtle.GetX();
}

当预期事件的序列覆盖另一个预期时,此属性可以与InSequence组合使用。在这种情况下,序列中的最后一个期望值必须标记为RetiresOnSaturation()。请注意,只需要标记最后一个期望值,因为当序列中的期望值饱和时,它会使先决条件期望值失效。

下面的示例演示了在实践中如何实现这一点。删除RetiresOnSaturation()会导致测试失败。

TEST(GmockStackoverflow, QuestionB)
{
MockTurtle turtle;
EXPECT_CALL(turtle, GetX()).WillOnce(Return(0));
{
InSequence s;
EXPECT_CALL(turtle, GetX()).WillOnce(Return(10));
EXPECT_CALL(turtle, GetX()).WillOnce(Return(10)).RetiresOnSaturation();
}
turtle.GetX();
turtle.GetX();
turtle.GetX();
}

根据我的经验,一些(好的,可能很多)开发人员遇到了一个问题,比如gtest错误消息,发现RetiresOnSaturation()使问题消失,然后养成了在整个单元测试中大量使用RetiresOnSaturation()的习惯,因为它解决了问题。这显然比推理测试用例应该完成什么更容易。另一方面,我喜欢思考必须按照什么顺序发生(根据文档中的API契约)——如果你使用After()或所有东西都不在同一序列中,这可能是部分顺序——这使得像InSequenceAfter()这样更具表达性的结构自然而然地出现在我的脑海中。

因此,正如Adam Casey所说,没有技术原因,但IMO可能存在神奇思维或训练不足的问题。

我建议避免使用RetiresOnSaturation()。它有一些一般性的问题(比如导致令人困惑的警告消息,请参阅下面的示例),但与替代方案相比,它的级别太低,如果你有干净的合同,并且正确使用前面提到的替代方案,那么它几乎是不需要的。你可以说这是最期待的goto

附录A:当一个免费的RetiresOnSaturation()导致更糟糕的消息时,是的,我看到过这样的代码:

EXPECT_CALL(x, foo()).WillOnce(Return(42)).RetiresOnSaturation();

如果x.foo()被调用不止一次,比方说两次,那么,如果没有RetiresOnSaturation(),你会收到一条错误消息,比如"没有对foo()的匹配期望…预期:被调用一次…实际:被调用两次(过饱和)",这条消息尽可能具体。但由于RetiresOnSaturation(),您只会得到一个"Unexpected function call foo()"警告,这是令人困惑和毫无意义的。

附录B:在您的示例中,也有可能在事后进行了使用InSequence的重构,而进行重构的人没有意识到RetiresOnSaturation()现在是多余的。你可以在你的版本控制系统中做一个"指责"来检查。

相关内容

  • 没有找到相关文章

最新更新