【问题标题】:How to mock malloc to return null in GMOCK?如何在 GMOCK 中模拟 malloc 以返回 null?
【发布时间】:2013-07-15 22:06:29
【问题描述】:

我想使用 Gmock 框架在 C++ 中模拟 malloc。可能吗?我已经尝试了所有可能的方法。但是托管这个 malloc 实现的类有一个私有构造函数和析构函数?

有什么方法可以直接mock malloc 返回NULL?

【问题讨论】:

  • 你可以看看DLL Injection/Library Interposing - 在 POSIX 和朋友上这工作得很好 - 有几个内存调试器依赖于这种机制 - 其中主要是 umem,以及许多依赖于此的标准分配器替换取得巨大成功的机制(nedmalloc、tcmalloc、umem、mtmalloc)。这可能比宏选项更好——因为它不需要更改现有代码——甚至不需要重新链接。

标签: c++ mocking googletest googlemock


【解决方案1】:

开发者爱,

首先,模拟标准库从来都不是一个好的做法,在这种粒度级别上测试代码是为艺术而艺术。您必须注意到,从一开始,测试就成为项目的一部分,如果您想让它们保持最新(即维护工作回归),您必须以与生产代码相同的方式考虑它们的设计。事实上,测试也是在项目生命周期中必须维护的代码,如果阅读、纠正和最终理解测试将花费太多时间,那么这种回归将毫无用处。尝试将其视为“生活文档”。

尽管如此,模拟标准 C 库的最丑陋的方法之一可能是静态钩子和宏。考虑以下示例:

#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

请注意,由于使用了预处理器宏,您不能用简单的 malloc 替换 mallocMock 函数名称。 希望对您有所帮助。

【讨论】:

    【解决方案2】:
    1. 包装malloc
    2. 将包装器传递给生产代码中的测试类 c'tor
    3. 模拟包装器(也可以在包装器之上创建接口并模拟它)
    4. 在测试代码中将 mock 传递给被测试的类 c'tor

      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))
      }
      

    【讨论】:

      【解决方案3】:

      glibcmock 可以帮助你模拟 malloc 和其他 libc 函数。

      #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));
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-08
        • 2018-12-25
        • 1970-01-01
        • 1970-01-01
        • 2015-06-14
        • 2016-05-24
        • 1970-01-01
        • 2021-12-24
        相关资源
        最近更新 更多