8

I have a test that works fine with a raw pointer, but I'm having trouble getting it work with a std::shared_ptr. The class is like this:

class MyClass
{
    MyClass(SomeService *service);
    void DoIt();
}

My test code is like:

    class MyClassTests : public ::testing::Test
    {
    public:
        MyClassTests():
            myClass_(new MyClass(&service_))
        {}

    protected:
        SomeServiceFake service_;
        MyClassSharedPointer myClass_;
    };

TEST_F(MyClassTests, DoIt_DoesNotMeetCriteria_DoesNotPerformAction) {

    // Arrange
    EXPECT_CALL(service_, MeetsCriteria(_))
        .WillRepeatedly(Return(false));

    EXPECT_CALL(service_, PerformAction(_))
        .Times(0);

    // Act
    myClass_->DoIt();
}

In this test, service_ is a mock/fake created on the stack in the test and I pass the address into the constructor of MyClass. Changing MyClass to take service as a shared_ptr, my new class looks like:

class MyClass
{
    MyClass(std::shared_ptr<SomeService> service);
    DoIt();
}

What I'm trying in my test is:

    class MyClassTests : public ::testing::Test
    {
    public:
        MyClassTests():
            myClass_(new MyClass(std::shared_ptr<SomeService>(&service_)))
        {

        }
            ...

When I do this, however, the test fails with a:

Debug Assertion Failed!
Expression: _CtrlIsValidHeapPointer(pUserData)

In a nutshell, I need a shared_ptr to service_ (which is a fake object) to pass to the MyClass constructor and I need a non-pointer for the EXPECT_CALL function. How can I get this to work correctly?

UPDATE

Tried dynamically allocating SomeServiceFake to get the shared_ptr and then using the * operator on service_, this gets me "further" but now I get the following error:

error : this mock object
(used in test MyClassTests.DoIt_DoesNotMeetCriteria_DoesNotPerformAction)
should be deleted but never is. Its address is @009BBA68.
1>EXEC : error : 1 leaked mock object found at program exit.

UPDATE 2

Using Mock::AllowLeak(service_.get()); so I can get around this problem for now. Hopefully I'll get an answer.

User
  • 62,498
  • 72
  • 186
  • 247

2 Answers2

9

Define your test class more like this:

class MyClassTests : public ::testing::Test {
 public:
  MyClassTests():
      service_(new SomeServiceFake), myClass_(new MyClass(service_)) {}
 protected:
  std::shared_ptr<SomeServiceFake> service_;
  std::shared_ptr<MyClass> myClass_;
};

and your test:

  EXPECT_CALL(*service_, MeetsCriteria(_))
      .WillRepeatedly(Return(false));

  EXPECT_CALL(*service_, PerformAction(_))
      .Times(0);
Fraser
  • 74,704
  • 20
  • 238
  • 215
  • 1
    This is an unfortunate shortcoming of gmock - it really doesn't play nice with smart pointers. I guess your actual code is somewhat more complex than what you've posted here? There are a few ways in which gmock can give a false positive about a leaked object managed by a smart pointer (e.g. see [here](http://stackoverflow.com/questions/10286514)). Without the actual code it's difficult to say why gmock reports the leak. – Fraser Apr 26 '12 at 22:21
2

This has nothing to do with the test framework. As you said yourself, you are creating a shared_ptr from a stack-allocated object (i.e. one with automatic lifetime). This does not make sense. Shared pointers are typically created from the result of new. You might be able to make it work if you pass a custom Deleter as the second argument to the shared_ptr constructor, but best might be to just create the object using new.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • Which makes perfect sense, but if I `new` `SomeServiceFake`, I believe googlemock expects class objects for the `EXPECT_CALL`, how do I achieve that? – User Apr 26 '12 at 21:48
  • User: Maybe say *service_ to get the reference and pass that to EXPECT_CALL? @VJovic: I don't understand your comment. – John Zwinck Apr 26 '12 at 22:05