Search code examples
c++unit-testinggoogletestgooglemock

Return reference to unique_ptr in google mock


I have problem returning a reference to a unique pointer in google mock. I have an object Foo, with a method operate(), that I’m trying to test in google test/google mock framework:

class Foo {
public:
  Foo(BarInterface &bar) : bar{bar} {};
  virtual ~Foo() = default;
  void operate() { bar.getBaz()->startMeUp(); }
private:
  BarInterface &bar;
};

The test class looks like this:

using ::testing::StrictMock;
using ::testing::ReturnRef;

class FooTest : public ::testing::Test {
protected:
  StrictMock<BarMock> barMock;
  std::unique_ptr<StrictMock<BazMock>> bazMock {new StrictMock<BazMock>()}; // This might be incorrect

  Foo *foo;
  virtual void SetUp() {
    foo = new Foo(barMock);
  }

  virtual void TearDown() {
    delete foo;
  }
};

TEST_F(FooTest, BasicTest) {
  EXPECT_CALL(barMock, getBaz()).WillOnce(ReturnRef(bazMock)); // Gives compilation error
  EXPECT_CALL(*bazMock, startMeUp()); // Gives compilation error
  foo->operate();
}

As you can see I have two objects that are mocked, Bar and Baz. Baz mock has one method, startMeUp():

class BazInterface {
public:
  virtual ~BazInterface() = default;
  virtual void startMeUp() = 0;
};

class BazMock : public BazInterface {
public:
  MOCK_METHOD0(startMeUp, void());
};

The Bar method getBaz() returns a reference to a unique pointer according to:

class BarInterface {
public:
  virtual ~BarInterface() = default;
  virtual std::unique_ptr<BazInterface>& getBaz() = 0;
};

class BarMock : public BarInterface {
public:
  MOCK_METHOD0(getBaz, std::unique_ptr<BazInterface>&());
};

The problem is (at least) that I can not get the two EXPECT_CALL() right. I’ve tried to return the bazMock in several ways, but I always get compilation error. I’ve also tried to simplify the problem by instead returning a reference to a shared_ptr and even an ordinary pointer, but I couldn’t get that compiling either. Can someone please help me to get it right?

Here is the compilation output:

gmock-actions.h: In instantiation of 'testing::internal::ReturnRefAction<T>::Impl<F>::Result testing::internal::ReturnRefAction<T>::Impl<F>::Perform(const ArgumentTuple&) [with F = std::unique_ptr<BazInterface>&(); T = std::unique_ptr<testing::StrictMock<BazMock> >; testing::internal::ReturnRefAction<T>::Impl<F>::Result = std::unique_ptr<BazInterface>&; testing::internal::ReturnRefAction<T>::Impl<F>::ArgumentTuple = std::tuple<>]':
foo_test.cc:30:1:   required from here
gmock-actions.h:683:14: error: invalid initialization of reference of type 'testing::internal::ReturnRefAction<std::unique_ptr<testing::StrictMock<BazMock> > >::Impl<std::unique_ptr<BazInterface>&()>::Result {aka std::unique_ptr<BazInterface>&}' from expression of type 'std::unique_ptr<testing::StrictMock<BazMock> >'
   return ref_;

Solution

  • The best fix would be to change the interface of BarInterface to return reference to BazInterface instead of reference unique_ptr. There is no need to expose the pointer to BarInterface users.
    If you insist on returning reference to unique_ptr do it like this:

    class BarMock : public BarInterface
    {
    public:
        BarMock(std::unique_ptr<BazInterface> baz) {this->baz = std::move(baz);}
    
        override std::unique_ptr<BazInterface>& getBaz(){
            getBazWrapped();
            return baz;
        }
        MOCK_METHOD0(getBazWrapped, void());
    private:
        std::unique_ptr<BazInterface> baz;
    };
    

    And in FooTest

    BazMock * bazMock { new <StrictMock<BazMock> };
    BarMock barMock { std::unique_ptr<BazInterface>(bazMock)};