How to specify consecutive returns in gmock?

26,577

Solution 1

ON_CALL is more used for setting default behavior of the function. I.e. you know that in tested code the mocked function is called, you want to set some default value, but it is not actually important how many times function is called.

The example:

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

To get your desired behavior I'd use expectations - you already provided some example in question, just to show more - an example when you expect 1, 2 then always 3:

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

EXPECT_CALL "way" might be troublesome when you want to set this in test fixture SetUp - and some tests might call foo only once. But, of course, there are ways to "control" ON_CALL return value for subsequent calls - but you must do it with special actions - like getting result of some function - like in this example:

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());

} 

Solution 2

@PiotrNycz's answer is correct and the preferred solution.

An alternative approach via a lambda function may give you more flexibility:

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

Related videos on Youtube

Paymahn Moghadasian
Author by

Paymahn Moghadasian

Updated on July 09, 2022

Comments

  • Paymahn Moghadasian
    Paymahn Moghadasian almost 2 years

    In Mockito we can specify multiple returns like (taken from here):

    //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);
    

    Is there a way to specify multiple returns for a mock made with gmock? Currently I have:

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

    which doesn't compile because I can't figure out multiple returns in gmock. Is this possible with gmock? If not, is there another way to solve this problem? I've found that we can EXPECT multiple return values like:

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

    However, I haven't found any docs for mocking multiple returns with ON_CALL.

  • Paymahn Moghadasian
    Paymahn Moghadasian over 8 years
    My understanding of expectations is that they are what we expect to be returned, not what should actually be returned by the mock. Is that incorrect? Your IncrementDummy example is really helpful. Kinda sucks that the best way to define multiple returns is so involved. :(
  • PiotrNycz
    PiotrNycz over 8 years
    If I understand you correctly - then yes. My example is very artificial - we never test by assertion what mocks returns - I just write this test to show that this mechanism works. More general we can say that EXPECT_CALLis for cases when we expects that mocked function is called from within tested code. It is not necessary to set "return value" - e.g. it is quite often that we expect void function to be called....
  • Mher Didaryan
    Mher Didaryan almost 5 years
    Hi, I tried to use this chain of WillOnces with InvokeArgument but it does not compile. In my case I have a callback which accepts error codes and I would like to invoke this callback with different error codes. EXPECT_CALL(*mockedObj, Start(_, _, _)).WillOnce(InvokeArgument<2>(Error::Success)).WillOnce(Inv‌​okeArgument<2>(Error‌​::InternalError)); Am I missing something or this kind of chaining will not work with InvokeArgument?
  • PiotrNycz
    PiotrNycz almost 5 years
    @MherDidaryan on which position in Start argument list do you have this callback? Maybe you made simple mistake with this index 2? The other possibility is that Start has different return value than your callback. Anyway - you probably have to ask question with this problem, attaching compiler output
  • PiotrNycz
    PiotrNycz almost 5 years
    @MherDidaryan you have to ask separate question describing the problem with simplified code that shows the problem with compiler version and output. There is no way to help you otherwise.
  • Mher Didaryan
    Mher Didaryan almost 5 years
    @PiotrNycz yes you are right this was a dumb mistake. Everything works as expected.
  • TUNAPRO1234
    TUNAPRO1234 about 2 years
    This is what I want - thanks!