问题 如何在gmock中指定连续返回?


在Mockito,我们可以指定多个回报(取自 这里):

//you can set different behavior for consecutive method calls.
 //Last stubbing (e.g: thenReturn("foo")) determines the behavior of further consecutive calls.
 when(mock.someMethod("some arg"))
  .thenReturn(new RuntimeException())
  .thenReturn("foo");

 //There is a shorter way of consecutive stubbing:
 when(mock.someMethod()).thenReturn(1,2,3);
 when(mock.otherMethod()).thenThrow(exc1, exc2);

有没有办法为使用gmock制作的模拟指定多个回报?目前我有:

store_mock_ = std::make_shared<StorageMock>();
ON_CALL(*store_mock_, getFileName(_)).Return("file1").Return("file2");

这不能编译,因为我无法弄清楚gmock中的多个返回。这可能与gmock?如果没有,还有另一种方法可以解决这个问题吗?我发现我们可以 EXPECT 多个返回值,如:

using ::testing::Return;...
EXPECT_CALL(turtle, GetX())
    .WillOnce(Return(100))
    .WillOnce(Return(200))
    .WillOnce(Return(300));

但是,我没有找到任何用于模拟多个返回的文档 ON_CALL


2447
2017-10-26 20:49


起源



答案:


ON_CALL 更多用于设置函数的默认行为。即你知道在测试代码中调用模拟函数,你想设置一些默认值,但实际上调用函数的次数并不重要。

  ON_CALL(foo, Sign(_))
      .WillByDefault(Return(-1));
  ON_CALL(foo, Sign(0))
      .WillByDefault(Return(0));
  ON_CALL(foo, Sign(Gt(0)))
      .WillByDefault(Return(1));

为了获得你想要的行为我会使用 期望  - 你已经提供了一些有问题的例子,只是为了展示更多 - 一个你期望的例子 12 永远 3

  EXPECT_CALL(foo, Sign(_))
      .WillOnce(Return(1))
      .WillOnce(Return(2))
      .WillRepeatedly(Return(3));

EXPECT_CALL 当你想在测试夹具中设置它时,“方式”可能会很麻烦 SetUp  - 有些测试可能会调用 foo 只有一次。但是,当然,有办法“控制” ON_CALL 后续调用的返回值 - 但您必须使用特殊操作执行此操作 - 例如获取某些函数的结果 - 如下例所示:

class IDummy
{
public:
    virtual int foo() = 0;
};

class DummyMock : public IDummy
{
public:
    MOCK_METHOD0(foo, int());
};
using namespace ::testing;
class DummyTestSuite : public Test
{
protected:
    DummyMock dummy;
    void SetUp() override
    {
        ON_CALL(dummy, foo())
           .WillByDefault(
                 InvokeWithoutArgs(this, &DummyTestSuite::IncrementDummy));
    }
    int dummyValue = 0;
    int IncrementDummy()
    {
        return ++dummyValue;
    }

};


TEST_F(DummyTestSuite, aaa)
{
    ASSERT_EQ(1, dummy.foo());
    ASSERT_EQ(2, dummy.foo());
    ASSERT_EQ(3, dummy.foo());

} 

12
2017-10-26 23:06



我对期望的理解是它们是我们期望返回的,而不是模拟实际返回的内容。这是不正确的?你的 IncrementDummy 例子真有帮助。有点认为定义多个退货的最佳方式是如此复杂。 :( - Paymahn Moghadasian
如果我理解正确 - 那么是的。我的例子非常人为 - 我们从不通过断言来测试mocks返回的内容 - 我只是编写这个测试来证明这个机制是有效的。更一般的我们可以这么说 EXPECT_CALL适用于我们希望从测试代码中调用mocked函数的情况。没有必要设置“返回值” - 例如通常我们期望调用void函数.... - PiotrNycz


答案:


ON_CALL 更多用于设置函数的默认行为。即你知道在测试代码中调用模拟函数,你想设置一些默认值,但实际上调用函数的次数并不重要。

  ON_CALL(foo, Sign(_))
      .WillByDefault(Return(-1));
  ON_CALL(foo, Sign(0))
      .WillByDefault(Return(0));
  ON_CALL(foo, Sign(Gt(0)))
      .WillByDefault(Return(1));

为了获得你想要的行为我会使用 期望  - 你已经提供了一些有问题的例子,只是为了展示更多 - 一个你期望的例子 12 永远 3

  EXPECT_CALL(foo, Sign(_))
      .WillOnce(Return(1))
      .WillOnce(Return(2))
      .WillRepeatedly(Return(3));

EXPECT_CALL 当你想在测试夹具中设置它时,“方式”可能会很麻烦 SetUp  - 有些测试可能会调用 foo 只有一次。但是,当然,有办法“控制” ON_CALL 后续调用的返回值 - 但您必须使用特殊操作执行此操作 - 例如获取某些函数的结果 - 如下例所示:

class IDummy
{
public:
    virtual int foo() = 0;
};

class DummyMock : public IDummy
{
public:
    MOCK_METHOD0(foo, int());
};
using namespace ::testing;
class DummyTestSuite : public Test
{
protected:
    DummyMock dummy;
    void SetUp() override
    {
        ON_CALL(dummy, foo())
           .WillByDefault(
                 InvokeWithoutArgs(this, &DummyTestSuite::IncrementDummy));
    }
    int dummyValue = 0;
    int IncrementDummy()
    {
        return ++dummyValue;
    }

};


TEST_F(DummyTestSuite, aaa)
{
    ASSERT_EQ(1, dummy.foo());
    ASSERT_EQ(2, dummy.foo());
    ASSERT_EQ(3, dummy.foo());

} 

12
2017-10-26 23:06



我对期望的理解是它们是我们期望返回的,而不是模拟实际返回的内容。这是不正确的?你的 IncrementDummy 例子真有帮助。有点认为定义多个退货的最佳方式是如此复杂。 :( - Paymahn Moghadasian
如果我理解正确 - 那么是的。我的例子非常人为 - 我们从不通过断言来测试mocks返回的内容 - 我只是编写这个测试来证明这个机制是有效的。更一般的我们可以这么说 EXPECT_CALL适用于我们希望从测试代码中调用mocked函数的情况。没有必要设置“返回值” - 例如通常我们期望调用void函数.... - PiotrNycz


@ PiotrNycz的答案是正确的,也是首选的解决方案。

通过lambda函数的另一种方法 可能 给你更多灵活性:

uint32_t callCount = 0;
ON_CALL(*turtle, GetX())
    .WillByDefault(testing::Invoke(
        [&callCount]() -> int {
            return ++callCount * 100;
        }
    ));

0
2018-03-19 12:14