我不理解以下gmock示例:
{
InSequence s;
for (int i = 1; i <= n; i++) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i))
.RetiresOnSaturation();
}
}
当我删除 .RetiresOnSaturation()时,以上代码以相同的方式工作- GetX 返回10、20,依此类推。当我们还使用 InSequence 对象时,使用 .RetiresOnSaturation()的原因是什么?你能解释一下吗?
答案 0 :(得分:1)
在给出的确切示例中,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();
}
答案 1 :(得分:1)
根据我的经验,一些(可能,可能很多)开发人员遇到问题,例如gtest错误消息,发现RetiresOnSaturation()
使问题消失了,然后养成了自由洒水{{1 }}进行单元测试–因为它可以解决问题。这显然比推理测试用例应该完成的事情容易。另一方面,我想根据发生什么顺序(根据文档 API合同)以什么顺序进行思考-如果您使用RetiresOnSaturation()
或不能按相同的顺序排列所有内容,这使After()
或InSequence
之类的更具表达力的结构在我脑海中自然浮现。
因此,正如亚当·凯西(Adam Casey)所说,这没有技术上的原因,但是IMO可能存在魔术思维或训练不足的问题。
我建议避免使用After()
。它有一些一般性问题(例如,引起混乱的警告消息,请参见下面的示例),但是与替代方案相比,它的级别太低,如果您拥有干净的合同并且正确使用上述替代方案,则几乎不需要它。您可以说这是gtest期望的RetiresOnSaturation()
…
附录A:一个示例性的goto
会带来更糟糕的消息的示例,是的,我已经看到了这样的代码:
RetiresOnSaturation()
如果EXPECT_CALL(x, foo()).WillOnce(Return(42)).RetiresOnSaturation();
被多次调用,比如说两次,那么如果没有x.foo()
,您将收到一条错误消息,例如“对foo()没有期望的匹配…预期:将被调用一次…实际:称为两次(过饱和)”,它尽可能具体。但是由于RetiresOnSaturation()
,您只会收到“意外的函数调用foo()”警告,这是令人困惑且毫无意义的。
附录B:在您的示例中,也有可能在事实发生之后进行重构以使用RetiresOnSaturation()
,并且进行重构的人员没有意识到InSequence
现在是多余的。您可以在版本控制系统中进行“怪”检查。