Passing arbitrary arguments to invocked methods with Google C++ Mocking Framework (Google Mock) (V1.5)
Asked Answered
C

2

15

I have a mock method. When it is called, I'd like it to call another function before calling its normal behavior. Something like :

EXPECT_CALL(*my_obj, MockedMethod(_,_,_,_,_,_))
    .WillOnce(DoAll(
        Invoke(my_obj, &SomeAdditionalMethodIWantToCall),
        Invoke(my_obj, &DefaultBehavior),
        ));

The only problem is that SomeAdditionalMethodIWantToCall expects parameter that not at all related to the one provided to MockedMethod. I'd like to be able to give them but I am struggling with the syntax. I wish there was something like (in fake syntax) :

EXPECT_CALL(*my_obj, MockedMethod(_,_,_,_,_,_))
    .WillOnce(DoAll(
        Invoke(my_obj, &SomeAdditionalMethodIWantToCall, arg1, arg2, arg3),
        Invoke(my_obj, &DefaultBehavior),
        ));

I have looked for such a thing in the documentation without any success.

In Using a Function or a Functor as an Action, we have :

  • Invoke(f), Invoke(object_pointer, &class::method), InvokeWithoutArgs(f), InvokeWithoutArgs(object_pointer, &class::method) which will just forward (or not) the parameter provided to the mocked function when it is called.

  • InvokeArgument<N>(arg1, arg2, ..., argk) seems to be for calling one of the parameter.

In Composite Actions

  • WithArg<N>(a) and WithArgs<N1, N2, ..., Nk>(a) seem to be to select which parameters from the original function get forwarded.

I guess I am missing something quite obvious but I am a bit stuck here so any suggestion will help.

Chromoplast answered 15/1, 2015 at 12:35 Comment(0)
M
9

One possible option would be to save the values of the arguments to class variables using the Assign action and then invoke the other function using a helper. Use the following expectation:

EXPECT_CALL(*my_obj, MockedMethod(_,_,_,_,_,_))
    .WillOnce(DoAll(
        Assign(&classVariable1, arg1),
        Assign(&classVariable2, arg2),
        Assign(&classVariable3, arg3),
        InvokeWithoutArgs(my_obj, &MyClass::SomeAdditionalMethodIWantToCallHelper),
        Invoke(my_obj, &MyClass::DefaultBehavior),
        ));

Then define your helper function as follows:

void MyClass::SomeAdditionalMethodIWantToCallHelper()
{
    SomeAdditionalMethodIWantToCall(classVariable1, classVariable2, classVariable3);
}

Edit

Another possible option is to write a custom action that takes in a pointer to a member function along with the arguments you wish to pass to it. This is closer to what you originally desired for syntax. Here is the custom action:

ACTION_P5(InvokeUnrelatedFunction, classPointer, pointerToMemberFunc,
          first, second, third)
{
    (classPointer->*pointerToMemberFunc)(first, second, third);
}

Here's how you would use it in an expectation:

EXPECT_CALL(*my_obj, MockedMethod(_,_,_,_,_,_))
    .WillOnce(DoAll(
        InvokeUnrelatedFunction(my_obj, &MyClass::SomeAdditionalMethodIWantToCall,
                                arg1, arg2, arg3),
        Invoke(my_obj, &MyClass::DefaultBehavior),
        ));
Mikiso answered 18/1, 2015 at 19:3 Comment(5)
With the InvokeUnrelatedFunction action, all i get is a compiler error saying that arg1 is not declared at the point where i try to invoke the action. What could be the cause of that?Pollinate
@Martin As stated in the question, arg1 is a "parameter not at all related to the one provided to MockedMethod." If you want to pass the arguments from the MockedMethod to a function, you can just use Invoke. You can also combine Invoke with WithArgsif you want to. Refer to the Google Mock Cookbook for an example.Mikiso
My compiler says some return value is requiredAbiosis
@ChristopherPisz You likely need to add a Return clause. For example: EXPECT_CALL(...).WillOnce(DoAll(Invoke(...),Return(someValue)));Mikiso
yea, the return value is for the mocked method. However, I need to do the invoke AFTER the mocked method returns. :/ I don't see a way.Abiosis
C
10

If you are using c++11, you can use lambda-functions like this:

EXPECT_CALL(*my_obj, MockedMethod(_,_,_,_,_,_))
.WillOnce(DoAll(
    InvokeWithoutArgs([&]() { 
        my_obj->SomeAdditionalMethodIWantToCall(arg1, arg2, arg3); 
    },
    Invoke(my_obj, &DefaultBehavior)   
));
Calcimine answered 23/11, 2017 at 13:26 Comment(2)
Very elegant! Thanks.Greenhorn
what is the method is private?Abiosis
M
9

One possible option would be to save the values of the arguments to class variables using the Assign action and then invoke the other function using a helper. Use the following expectation:

EXPECT_CALL(*my_obj, MockedMethod(_,_,_,_,_,_))
    .WillOnce(DoAll(
        Assign(&classVariable1, arg1),
        Assign(&classVariable2, arg2),
        Assign(&classVariable3, arg3),
        InvokeWithoutArgs(my_obj, &MyClass::SomeAdditionalMethodIWantToCallHelper),
        Invoke(my_obj, &MyClass::DefaultBehavior),
        ));

Then define your helper function as follows:

void MyClass::SomeAdditionalMethodIWantToCallHelper()
{
    SomeAdditionalMethodIWantToCall(classVariable1, classVariable2, classVariable3);
}

Edit

Another possible option is to write a custom action that takes in a pointer to a member function along with the arguments you wish to pass to it. This is closer to what you originally desired for syntax. Here is the custom action:

ACTION_P5(InvokeUnrelatedFunction, classPointer, pointerToMemberFunc,
          first, second, third)
{
    (classPointer->*pointerToMemberFunc)(first, second, third);
}

Here's how you would use it in an expectation:

EXPECT_CALL(*my_obj, MockedMethod(_,_,_,_,_,_))
    .WillOnce(DoAll(
        InvokeUnrelatedFunction(my_obj, &MyClass::SomeAdditionalMethodIWantToCall,
                                arg1, arg2, arg3),
        Invoke(my_obj, &MyClass::DefaultBehavior),
        ));
Mikiso answered 18/1, 2015 at 19:3 Comment(5)
With the InvokeUnrelatedFunction action, all i get is a compiler error saying that arg1 is not declared at the point where i try to invoke the action. What could be the cause of that?Pollinate
@Martin As stated in the question, arg1 is a "parameter not at all related to the one provided to MockedMethod." If you want to pass the arguments from the MockedMethod to a function, you can just use Invoke. You can also combine Invoke with WithArgsif you want to. Refer to the Google Mock Cookbook for an example.Mikiso
My compiler says some return value is requiredAbiosis
@ChristopherPisz You likely need to add a Return clause. For example: EXPECT_CALL(...).WillOnce(DoAll(Invoke(...),Return(someValue)));Mikiso
yea, the return value is for the mocked method. However, I need to do the invoke AFTER the mocked method returns. :/ I don't see a way.Abiosis

© 2022 - 2024 — McMap. All rights reserved.