Gmock-InSequence与RetiresOnSaturation

时间:2018-10-11 17:31:10

标签: googletest gmock

我不理解以下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()的原因是什么?你能解释一下吗?

2 个答案:

答案 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现在是多余的。您可以在版本控制系统中进行“怪”检查。