Google mock ByRef method

Rodrigo Vasconcelos picture Rodrigo Vasconcelos · Jun 21, 2013 · Viewed 19.7k times · Source

I have a class that takes a boolean as a reference parameter and returns an integer:

class Foo
{
  public:
    Bar my_bar;
    virtual int myMethod(bool &my_boolean) = 0;
}

/*...*/

int Foo::myMethod(bool &my_boolean){
  if (my_bar == NULL){
    my_boolean = false;
    return -1;
  }
  else{
    my_boolean = true;
    return 0;
  }

}

And I created a mock for this class:

class MockFoo : public Foo
{
   MOCK_METHOD1(myMethod,int(bool &my_boolean));
}

I'm having problems on how to set the expectations for this kind of function,because I need to set the return value and the reference parameter to specific values to properly create my unit tests.How can I deal with this kind of function with gmock?I tried following what I thought was the solution on the documentation:

using ::testing::SetArgPointee;

class MockMutator : public Mutator {
  public:
  MOCK_METHOD2(Mutate, void(bool mutate, int* value));
  ...
};
  ...

MockMutator mutator;
EXPECT_CALL(mutator, Mutate(true, _))
  .WillOnce(SetArgPointee<1>(5));

But either I didn't understood the example or it wasn't applicable for this case.Has anyone dealt whith this kind of situation before?

Thanks in advance.

Answer

πάντα ῥεῖ picture πάντα ῥεῖ · Jun 21, 2013

Your question is hard to get! The samples from google mocks 'cook book' are so as well.

Do you want to reuse the implementation for Foo::myMethod() with you mock class, or do you just want to mock the side effects (return value and changed by ref parameters) for specific call situations?

A mock class is usually meant to replace / simulate your Foo class, not to inherit it directly or it's behavior. Don't know if the way you define this 'default' behavior for a pure method will work, but doubt that. You might simply omit the = 0 then. The better approach would be to separate out a real interface declaration like:

struct IFoo
{
    virtual int myMethod(bool &my_boolean) = 0;
    virtual ~IFoo() {}
};

class Foo : public IFoo
{
    // ...
};

class MockFoo : public IFoo
{
   MOCK_METHOD1(myMethod,int(bool &my_boolean));
};

If you have the latter case, you should get off with testing::Return(value) and testing::SetArgReferee<N>(value) (found that in the very useful 'Cheat Sheet').

Your expectation call should look like this then:

MockFoo foo;

// Expect call to myMethod() return -1 and set the by ref argument to true
EXPECT_CALL(foo, myMethod(_))
  .WillOnce(DoAll(SetArgReferee<0>(true),Return(-1)));

// Expect call to myMethod() return 0 and set the by ref argument to false
EXPECT_CALL(foo, myMethod(_))
  .WillOnce(DoAll(SetArgReferee<0>(false),Return(0)));

If you really want to reuse your original classes logic for myMethod() have a look at 'Delegating calls to a parent class', resp. 'Delegating Calls to a Real Object'