我想使用 Gmock 框架在 C++ 中模拟 malloc。可能吗?我已经尝试了所有可能的方法。但是托管这个 malloc 实现的类有一个私有构造函数和析构函数?
有什么方法可以直接模拟 malloc 以返回 NULL?
我想使用 Gmock 框架在 C++ 中模拟 malloc。可能吗?我已经尝试了所有可能的方法。但是托管这个 malloc 实现的类有一个私有构造函数和析构函数?
有什么方法可以直接模拟 malloc 以返回 NULL?
开发者爱,
首先,模拟标准库从来都不是一个好的做法,在这种粒度级别上测试代码是为艺术而艺术。您必须注意到,从一开始,测试就成为项目的一部分,如果您想让它们保持最新(也就是维护工作回归),您必须以与生产代码相同的方式考虑它们的设计。事实上,测试也是在项目生命周期中必须维护的代码,如果阅读、纠正和最终理解测试将花费太多时间,那么这种回归将毫无用处。尝试将其视为“生活文档”。
然而,模拟标准 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 函数名称。希望对您有所帮助。
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));
}
将模拟传递给测试代码中的测试类 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))
}