GMock - returning default value with ON_CALL for overloaded methods

lgromanowski picture lgromanowski · May 10, 2013 · Viewed 13.2k times · Source

I'm trying to write mock for a class which contains three overloaded methods, ie.:

#include <gtest/gtest.h>
#include <gmock/gmock.h>

using ::testing::_;
using ::testing::Return;
using ::testing::A;
using ::testing::ByRef;
using ::testing::Ref;
using ::testing::TypedEq;

struct Foo {
  int fooMethod(const int& intParam) { return 0; }
  int fooMethod(const float& floatParam) { return 0; }
  int fooMethod(const std::string& stringParam) { return 0; }
};

struct FooMock {
  FooMock() {
    ON_CALL(*this, fooMethod(_)).WillByDefault(Return(-1));
  }

  MOCK_METHOD1(fooMethod, int(const int& intParam));
  MOCK_METHOD1(fooMethod, int(const float& floatParam));
  MOCK_METHOD1(fooMethod, int(const std::string& stringParam));
};

but this gives an error:

 error: call of overloaded ‘gmock_fooMethod(const testing::internal::AnythingMatcher&)’ is ambiguous

I've also tried TypedEq() instead of "_", but it gives more obscure errors. I've checked GMock FAQ, Wiki and I didn't find solution - how can I return default value with ON_CALL for overloaded methods?

BR, Lukasz

Answer

Fraser picture Fraser · May 15, 2013

@tx34 has the crux of the answer, but there are a few more issues in the code.

Firstly, the docs on Selecting Between Overloaded Functions are most appropriate. You have three overloads of fooMethod with the same number of arguments but different argument types. You're going to have to use a matcher that specifies the type.

Next, you need to define all your Foo functions which are to be mocked as virtual, or else invoking them through a Foo object won't call the derived mock functions. Since you're defining Foo as a base class, it should also have a virtual destructor to avoid slicing.

Finally, you need to have FooMock inherit from Foo.

So putting it all together, you end up with something like:

#include <memory>
#include <string>
#include "gtest/gtest.h"
#include "gmock/gmock.h"

using ::testing::_;
using ::testing::An;
using ::testing::Matcher;
using ::testing::TypedEq;
using ::testing::Return;

struct Foo {
  virtual ~Foo() {}
  virtual int fooMethod(const int&) { return 0; }
  virtual int fooMethod(const float&) { return 0; }
  virtual int fooMethod(const std::string&) { return 0; }
};

struct FooMock : Foo {
  FooMock() : Foo() {
    ON_CALL(*this, fooMethod(An<const int&>())).
        WillByDefault(Return(-1));
    ON_CALL(*this, fooMethod(Matcher<const float&>(_))).
        WillByDefault(Return(-2));
    ON_CALL(*this, fooMethod(TypedEq<const std::string&>("1"))).
        WillByDefault(Return(-3));
  }

  MOCK_METHOD1(fooMethod, int(const int& intParam));
  MOCK_METHOD1(fooMethod, int(const float& floatParam));
  MOCK_METHOD1(fooMethod, int(const std::string& stringParam));
};

TEST(Foo, foo) {
  std::shared_ptr<Foo> foo(new FooMock);
  auto foo_mock(std::dynamic_pointer_cast<FooMock>(foo));

  EXPECT_CALL(*foo_mock, fooMethod(Matcher<const int&>(_))).Times(1);
  EXPECT_CALL(*foo_mock, fooMethod(Matcher<const float&>(_))).Times(1);
  EXPECT_CALL(*foo_mock, fooMethod(Matcher<const std::string&>(_))).Times(1);

  EXPECT_EQ(-1, foo->fooMethod(1));
  EXPECT_EQ(-2, foo->fooMethod(1.0f));
  EXPECT_EQ(-3, foo->fooMethod("1"));
}


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