Search code examples
c++googletestgooglemock

How to pass extra argument to google mock EXPECT_CALL


I'm testing My C++ class that uses a dependency via an interface. I have mocked the interface and have a complex lambda that I use in GMock's EXPECT_CALL to verify that my class calls the mocked function correctly. Function is called several times during one call to the API of my class. The correct behavior is different in different calls, so I would like to supply my checker a different expected result in different calls.

How can I give different expected result for my lambda in EXPECT_CALL(..).WillOnce(lambda)? Meaning something like this:

EXPECT_CALL(..)
  .WillOnce(InvokeWithExtraArgs(lambda, expectedResult1)),
  .WillOnce(InvokeWithExtraArgs(lambda, expectedResult2)),

Full example:

#include "gtest/gtest.h"
#include "gmock/gmock.h"

using namespace testing;

struct Dependency
{
    virtual void foo (double d) = 0;
};

struct DependencyMock : public Dependency
{
    MOCK_METHOD (void, foo, (double), (override));
};

struct Service
{
    Service (Dependency *d) : dep {d} {};
    void doStuff ()
    {
        dep->foo (1.2);
        dep->foo (2.3);
    }
    Dependency *dep;
};

TEST (mytest, test1)
{
    DependencyMock depMock;
    Service service {&depMock};

    auto fooVerifier = [] (double d /*, int expectedResult - is this possible? */ )
    {
        auto result = d + 123;     // some lengthy logic here to deduce if foo() was called correctly
        auto expectedResult = 234; // <<< how to get this as an argument
        EXPECT_EQ (result, expectedResult);
    };

    EXPECT_CALL (depMock, foo (_))
        .Times(2)
        .WillOnce (Invoke (fooVerifier))   // <<< How can I give expected result for above EXPECT_EQ here?
        .WillOnce (Invoke (fooVerifier));  // <<< How can I give expected result for above EXPECT_EQ here?
    service.doStuff ();
}

int main (int argc, char *argv[])
{
    ::testing::InitGoogleTest (&argc, argv);
    return RUN_ALL_TESTS ();
}

Solution

  • Sounds like you want a matcher, not a special Invoke.

    MATCHER_P(FooArgIsCorrect, expected, "")
    {
        auto result = arg + 123; // your length calculation go here
        return result == expected;
    }
    

    Then, in test:

    EXPECT_CALL (depMock, foo (FooArgIsCorrect(FirstExpectedValue))).RetiresOnSaturation();
    EXPECT_CALL (depMock, foo (FooArgIsCorrect(SecondExpectedValue))).RetiresOnSaturation();
    

    If your real case has something that needs to be calculated when the function is called (because e.g. your return value depends on it), you can still use Invoke with lambdas, just pass the extra argument via capture list:

        auto fooVerifier = [] (double d, int expectedResult)
        {
            auto result = d + 123;     // some lengthy logic here to deduce if foo() was called correctly
            auto expectedResult = 234; // <<< how to get this as an argument
            EXPECT_EQ (result, expectedResult);
        };
    
        EXPECT_CALL (depMock, foo (_))
            .Times(2)
            .WillOnce (Invoke ([expected](double d){return fooVerifier(d, expected);}))  
            .WillOnce (Invoke ([expected](double d){return fooVerifier(d, expected);}));