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.

SylvainD
  • 1,743
  • 1
  • 11
  • 27

2 Answers2

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)   
));
Myon
  • 937
  • 13
  • 23
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),
        ));
RA.
  • 7,542
  • 1
  • 34
  • 35
  • 1
    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? – Martin G Aug 08 '16 at 11:29
  • @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 `WithArgs`if you want to. Refer to the Google Mock Cookbook for an example. – RA. Aug 08 '16 at 20:39
  • My compiler says some return value is required – Christopher Pisz Jun 04 '21 at 16:10
  • @ChristopherPisz You likely need to add a `Return` clause. For example: `EXPECT_CALL(...).WillOnce(DoAll(Invoke(...),Return(someValue)));` – RA. Jun 04 '21 at 18:02
  • 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. – Christopher Pisz Jun 04 '21 at 19:32