How to mock malloc to return null in GMOCK?
Asked Answered
B

3

8

I want to mock malloc in C++ using Gmock framework. Is it possible? I have tried all possible ways. But the class which is hosting this malloc implementation has got a private constructor and destructor?

Is there any way in which we can directly mock malloc to return NULL?

Binate answered 15/7, 2013 at 22:6 Comment(1)
You could look at DLL Injection/Library Interposing - on POSIX and friends this works quite well - there are several memory debuggers that rely on this mechanism - chief among them umem, and many standard allocator replacements which rely on this mechanism with great success (nedmalloc, tcmalloc, umem, mtmalloc). This is maybe better than the macro option - as it requires no change to existing code - not even a re-link.Cardon
G
1

DeveloperLove,

first of all mocking of standard library is never a good practice and testing the code on such granulation level is art for art's sake. You have to notice that from very beginning, tests become the part of the project and if you want to keep them up-to-date (aka maintaing working regression) you have to think about their design in the same way as production code. In fact tests are also the code which has to be maintained during lifetime of project and if reading, correcting and finnaly understading that tests will take too much time, such regression will be useless. Try to think about it as the "life documentation".

Nevertheless, probably one of the ugliest way to mock the standard C library is static hook and macros. Consider the following example:

#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <boost/bind.hpp>
#include <boost/function.hpp>

static boost::function<void*(size_t)> malloc_bridge;

struct StdlibMock
{
    StdlibMock()
    {
        malloc_bridge = boost::bind(&StdlibMock::mallocMock, this, _1);
    }
    MOCK_METHOD1(mallocMock, void*(size_t));
};  // struct Struct StdlibMock

void* malloc_cheat(size_t size)
{
    return malloc_bridge(size);
}

#define malloc malloc_cheat

struct Sut
{
    void f()
    {
        malloc(10);
    }
};

struct TestWithMalloc : ::testing::Test
{
    StdlibMock stdlibMock;
};  // struct TestWithMalloc

TEST_F(TestWithMalloc, ShouldMalloc10Bytes)
{ 
    EXPECT_CALL(stdlibMock, mallocMock(10))
      .WillOnce(::testing::Return(static_cast<void*>(0)));
    Sut sut;
    sut.f();
}

#undef malloc

Notice that you cannot replace the mallocMock function name with simple malloc because of using of preprocessor macro. Hopefully, was a little bit helpful.

Godber answered 15/7, 2013 at 23:6 Comment(0)
B
0
  1. Wrap malloc
  2. Pass the wrapper to the tested class c'tor in production code
  3. Mock the wrapper (can also create interface above the wrapper and mock it)
  4. Pass the mock to the tested class c'tor in test code

    class I_mallocWrapper
    {
        public:
        virtual ~I_mallocWrapper() {}
        virtual void* myMalloc (size_t size) = 0;
    };
    
    //wrapper to malloc
    class mallocWrapper : public I_mallocWrapper
    {
    public:
        virtual void* myMalloc (size_t size)    {return malloc(size);}
        virtual ~mallocWrapper() {}
        mallocWrapper(){}
    };
    
    //tested class with tested method that uses the wrapper
    class TestedClass
    {
    public:
        TestedClass(I_mallocWrapper* mallocW) { this->m_mallocWrapper = mallocW; }
        void testedMethod(size_t size) { m_mallocWrapper->myMalloc(size); }
        virtual ~TestedClass() {}
    private:
        I_mallocWrapper* m_mallocWrapper;
    };
    
    //production code
    void main()
    {
        size_t size = 18;
        I_mallocWrapper* MW = new mallocWrapper;
        TestedClass* TC = new TestedClass(MW);
        TC->testedMethod(size);
    }
    
    //mock the wrapper
    class mockMallocWrapper : public I_mallocWrapper
    {
    public:
       MOCK_METHOD1(myMalloc, void*(size_t size));
    };
    
    //test code
    TEST(MallocTest,callMalloc)
    {
        size_t size = 18;
        I_mallocWrapper* MW = new mockMallocWrapper;
        TestedClass* TC = new TestedClass(MW);
        TC->testedMethod(size);
    
        EXPECT_CALL(MW, myMalloc(_))
           .WillOnce(Return(NULL))
    }
    
Baluster answered 10/1, 2017 at 18:49 Comment(0)
D
0

glibcmock can help you mock malloc and other libc function.

#include "got_hook.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include <mutex>
#include <memory>

struct MockMalloc {
    MOCK_METHOD1(Malloc, void *(size_t));
};

static MockMalloc *g_mock{nullptr};

static void *Malloc(size_t size) {
    return g_mock->Malloc(size);
}

static std::mutex g_test_mutex;

TEST(MallocTest, ReturnNull) {
    std::lock_guard<std::mutex> lock(g_test_mutex);
    std::unique_ptr<MockMalloc> mock(g_mock = new MockMalloc());
    testing::GotHook got_hook;
    ASSERT_NO_FATAL_FAILURE(got_hook.MockFunction("malloc", (void*)&Malloc););
    // ... do your test here, for example:
    EXPECT_CALL(*g_mock, Malloc(testing::_)).WillOnce(testing::Return(nullptr));
    EXPECT_EQ(nullptr, malloc(1));
}
Derickderide answered 12/3, 2017 at 1:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.