Google mock global mock object memory leak

爷,独闯天下 提交于 2019-12-11 07:00:43

问题


I am using VS2005, and C++ for unit testing using google mock.
I had a global free function in unit testing, and I used the following code to mock free function:

NiceMock <MockA> mockObj;  



struct IFoo {  
    virtual A* foo() = 0;  
    virtual ~IFoo() {}  
};  

struct FooMock : public IFoo {  
    FooMock() {}  
    virtual ~FooMock() {}  
    MOCK_METHOD0(foo, A*());  
};

FooMock fooMock;

// foo() implementation  
A* foo() {  
    return fooMock.foo();  
}  

In the SetUp() function, I set Expectations on the global object like

EXPECT_CALL(fooMock,foo())  
    .Times(1)  
    .WillOnce(Return(&mockObj));  

TEST(..., instA) {

    // ...
}

and in TearDown(), I delete the global mock object fooMock

virtual TearDown(){  
    delete &fooMock;  
}  

When I run the code, I get the following error

Error: Memory Leak in xyz.instA,

also,
0 bytes in 0 Free Blocks.
-61 bytes in -1 Normal Blocks.
68 bytes in 7 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 11025 byte
Total allocations: 50602 bytes.

Can anyone tell me what is happening here? If I don't delete fooMock, I get the error "fooMock should be delete but never is", or Heap corruption detected.
From the error, I can see that somewhere my heap is being mishandled, but I cannot find the point. I have tried to debug it step by step as well.

Some help would be really great! :)


回答1:


It looks like the problem is that you're instantiating a global instance of FooMock. Googlemock/googletest expect the mock to be defined either within the body of the test, or within a test fixture class.

In the example above, you'd simply instantiate fooMock inside the test:

TEST(..., instA) {

    FooMock fooMock;
    // ...
}



回答2:


As Ian stated:

Googlemock/googletest expect the mock to be defined either within the body of the test, or within a test fixture class.

The idea behind it is explained in the Cookbook:

When it's being destroyed, your friendly mock object will automatically verify that all expectations on it have been satisfied, and will generate Google Test failures if not. This is convenient as it leaves you with one less thing to worry about. That is, unless you are not sure if your mock object will be destroyed.

In your case fooMock is a global variable (and as you stated it must stay this way) so after each test you just need to run manual verification:

    using ::testing::Mock;

    TEST(..., instA) 
    {
       ASSERT_TRUE(
           Mock::VerifyAndClearExpectations(
            &fooMock));
    }

Since it is a global variable you can also just do:

Mock::AllowLeak(&fooMock);

More details in Cookbook - Forcing a Verification and CheatSheet - Verifying and Resetting a Mock:




回答3:


So I stumbled upon this question and couldn't figure out a way. But then being a software engineer, I needed to find a solution. So here is what I did.

Suppose you want to mock a Queue. The one function you want to mock is dequeue. I will assume you want to dequeue integers to keep things simple because I want to demonstrate how to make global mocks without memory leaks.

class QueueInterface {
    public:
        virtual ~QueueInterface() {};
        virtual int dequeue() = 0;
};

class QueueMock : public QueueInterface {
    public:
        virtual ~QueueMock() {};
        MOCK_METHOD(int, dequeue, (), (override));
};

// Instead of a global object, have a global pointer
QueueMock *globalQueue;

class TestFixture : public ::testing::Test {
    protected:
        QueueMock mockedQueue;

        void SetUp() {
            globalQueue = &mockedQueue; // Point the global pointer to this queue
        }

        void TearDown() {
            globalQueue = NULL;
        }
}

// Now you can use this global queue pointer in free function or
// C style functions and override the existing implementations.
// This way you can mock a global object.

int dequeueFromQueue() {
   return globalQueue->dequeue();
}

TEST_F(TestFixture, DEQUEUE_TEST) {
    // Write your test here to use global queue pointer
    // Deref pointer to get mocked object
    EXPECT_CALL(*globalQueue, dequeue);
}

In this way, whenever a new test is executed, the member variable mockedQueue is allocated and then deallocated at the end of the test. The globalQueue would point to the member instance of each test every time.

Hope this helps! :)



来源:https://stackoverflow.com/questions/28475881/google-mock-global-mock-object-memory-leak

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!