Search code examples
c++referencegoogletestgooglemock

How to ignore the first action in the gtest DoAll()


I declare a function

void MyFunction(const std::wstring& inParameter, std::wstring& outParamater);

The first parameter is a passed in parameter, the second one is the value out parameter, the value I want to get by the function will pass it out by outParameter.

Now I Gmock it

MOCK_METHOD2(MyFunction, void(const std::wstring&, std::wstring&));

However, when I use this mock function:

std::wstring firstStr = L"firstStr";
std::wstring test = L"test";
EXPECT_CALL(*myGmockInstance, MyFunction(firstStr, _)).Times(1).WillOnce(DoAll(firstStr, SetArgReferee<1>(test)));

It doesn't work.

I also tried

EXPECT_CALL(*myGmockInstance, MyFunction(_, _)).Times(1).WillOnce(DoAll(_, SetArgReferee<1>(test)));

or

EXPECT_CALL(*myGmockInstance, MyFunction(_, _)).Times(1).WillOnce(DoAll(firstStr, SetArgReferee<1>(test)));

or

EXPECT_CALL(*myGmockInstance, MyFunction(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<0>(firstStr), SetArgReferee<1>(test)));

I understand that the inParameter is const, so I cannot use SetArgReferee for it. But how to set its value and at the same time I can set value for outParameter?


Solution

  • I think that the title of your question is quite misleading. From what I understand, you just want to assign some arbitrary value to your function's second argument (the output argument). This is how you can do it using Invoke:

    using ::testing::_;
    
    void assignStringToArg(const std::wstring&, std::wstring& outputStr,
        const std::wstring expectedStr) {
        outputStr = expectedStr;
    }
    
    class SomeMock {
    public:
        MOCK_METHOD2(MyFunction, void(const std::wstring&, std::wstring&));
    };
    
    TEST(xxx, yyy) {
        SomeMock someMock;
        std::wstring firstStr(L"aaabbbccc");
        std::wstring secondStr(L"I should change upon MyFunction call ...");
        std::wstring expectedSecondStr(L"xxxyyyzzz");
        EXPECT_CALL(someMock, MyFunction(firstStr, _)).Times(1).WillOnce(Invoke(std::bind(
            &assignStringToArg,
            std::placeholders::_1,
            std::placeholders::_2,
            expectedSecondStr)));
        someMock.MyFunction(firstStr, secondStr);
        ASSERT_EQ(expectedSecondStr, secondStr);
    }
    

    Note that the function provided to Invoke must have the same signature as the function that you expect to be called (that's why I use bind). You can achieve the same result using google macro ACTION_P. I prefer to use Invoke only because it looks more clean to me.

    Since your case is rather simple, you can also do it using SetArgReferee like you tried before:

        EXPECT_CALL(someMock, MyFunction(firstStr, _)).Times(1).WillOnce(
            SetArgReferee<1>(L"something"));
        someMock.MyFunction(firstStr, secondStr);
        ASSERT_EQ(L"something", secondStr);
    

    I just see no point using DoAll if you only want to do one action. But ... if you really insist:

        EXPECT_CALL(someMock, MyFunction(firstStr, _)).Times(1).WillOnce(
            DoAll(SetArgReferee<1>(L"something1"), SetArgReferee<1>(L"something2")));
        someMock.MyFunction(firstStr, secondStr);
        ASSERT_EQ(L"something2", secondStr);
    

    It is rather stupid example, because it set's the output variable to L"something1" and then immediately to L"something2".