Avoid matching .WillOnce multiple times in Google Mock
Asked Answered
E

3

31

I have a mock object setup that looks like this:

MyObject obj;
EXPECT_CALL(obj, myFunction(_))
.WillOnce(Return(1))
.WillOnce(Return(1))
.WillOnce(Return(1))
.WillRepeatedly(Return(-1));

Is there a way to not have to repeat .WillOnce(Return(1)) three times?

Ebullient answered 7/8, 2013 at 19:45 Comment(1)
BTW: You're not 'running' but 'matching' Return(x).Preparation
A
49

You can use .Times(nn) followed by .WillRepeatedly(... to solve this:

using testing::InSequence;

MyObject obj;

{
  InSequence s;
  EXPECT_CALL(obj, myFunction(_))
      .Times(3)
      .WillRepeatedly(Return(1));
  EXPECT_CALL(obj, myFunction(_))
      .WillRepeatedly(Return(-1));
}
Antipodes answered 8/8, 2013 at 16:24 Comment(3)
Ah! Didn't know these can be combined this way. That looks much easier than my proposal :-) ...Preparation
or EXPECT_CALL(...).WillRepeatedly(Return(-1)); EXPECT_CALL(...).Times(3).WillRepeatedly(Return(1).RetiresOnSaturation(); which looks a little overkill here, but there are other cases where it could be helpful.Anatto
Currently this function executes only 2 times for my codeOvershoe
A
5

For completeness' sake, there's another standard/simple option, though the accepted answer seems clearer in this case.

EXPECT_CALL(obj, myFunction(_)).WillRepeatedly(Return(-1));
EXPECT_CALL(obj, myFunction(_)).Times(3).WillRepeatedly(Return(1)).RetiresOnSaturation();

This can be useful if you know what you want your last/default response to be (-1), but want to muck with the number of times its called before then.

Anatto answered 30/10, 2015 at 19:12 Comment(1)
RetiresOnSaturation() was exactly what I needed, thanks.Ochre
I
1

I'm afraid there's no other way to configure this behavior. Can't find an obvious way in the documentation at least.

You'll might get off this problem introducing an appropriate user defined matcher though, that keeps track of a calling count and threshold you can provide from your testcases via template parameters (don't actually know how to induce the ResultType automatically :-( ):

using ::testing::MakeMatcher;
using ::testing::Matcher;
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;

template
    < unsigned int CallThreshold
    , typename ResultType
    , ResultType LowerRetValue
    , ResultType HigherRetValue
    >
class MyCountingReturnMatcher 
: public MatcherInterface<ResultType>
{
public:
    MyCountingReturnMatcher()
    : callCount(0)
    {
    }

    virtual bool MatchAndExplain
        ( ResultType n
        , MatchResultListener* listener
        ) const 
    {
        ++callCount;
        if(callCount <= CallThreshold)
        {
            return n == LowerRetValue;
        }

        return n == HigherRetValue;
    }

    virtual void DescribeTo(::std::ostream* os) const 
    {
        if(callCount <= CallThreshold)
        {
            *os << "returned " << LowerRetValue;
        }
        else
        {
            *os << "returned " << HigherRetValue;
        }
    }

    virtual void DescribeNegationTo(::std::ostream* os) const 
    {
        *os << " didn't return expected value ";
        if(callCount <= CallThreshold)
        {
            *os << "didn't return expected " << LowerRetValue 
                << " at call #" << callCount;
        }
        else
        {
            *os << "didn't return expected " << HigherRetValue 
                << " at call #" << callCount;
        }
    }

private:
    unsigned int callCount;
};

template
    < unsigned int CallThreshold
    , typename ResultType
    , ResultType LowerRetValue
    , ResultType HigherRetValue
    >
inline Matcher<ResultType> MyCountingReturnMatcher() 
{
    return MakeMatcher
               ( new MyCountingReturnMatcher
                    < ResultType
                    , CallThreshold 
                    , ResultType
                    , LowerRetValue
                    , HigherRetValue
                    >()
               );
}

Use then to expect a certainly counted call result:

EXPECT_CALL(blah,method)
   .WillRepeatedly(MyCountingReturnMatcher<1000,int,1,-1>()) // Checks that method
                                                             // returns 1000 times 1
                                                             // but -1 on subsequent 
                                                             // calls.

NOTE
I didn't check this code to be working as intended, but it should guide you into the right direction.

Indite answered 7/8, 2013 at 21:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.