Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using googlemock EXPECT_CALL with shared_ptr?

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.

like image 886
User Avatar asked Apr 26 '12 21:04

User


2 Answers

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);
like image 80
Fraser Avatar answered Oct 05 '22 22:10

Fraser


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.

like image 36
John Zwinck Avatar answered Oct 06 '22 00:10

John Zwinck