gmock 如何mock一个模板类单例

下面是一个简单的办法:

#include <gtest/gtest.h>
#include <gmock/gmock.h>

using ::testing::Return;
using ::testing::_;

template<typename T>
class mockFoo{
public:
    static mockFoo& GetInstance(){
        static mockFoo instance;
        return instance;
    }
    MOCK_METHOD(T, bar, (const T&), ());
protected:
    mockFoo() = default;
    ~mockFoo() = default;
    mockFoo(const mockFoo&) = delete;
    mockFoo& operator=(const mockFoo&) = delete;
};

class fooTest : public ::testing::Test {
protected:
    void SetUp() override {
    }
    void TearDown() override {
    }
};

TEST_F(fooTest, fooTest1){
    auto& ins = mockFoo<int>::GetInstance();
    EXPECT_CALL(ins, bar(_)).WillOnce(Return(42));
    EXPECT_EQ(ins.bar(1), 42);
}

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

红帽系安装gtest:

sudo dnf install gtest gtest-devel gmock-devel

编译:

g++ -std=c++17 main.cpp -lgtest -lgmock -lpthread -o test

当然,实际情况是,单例里面本身没有mock method,那我们就得创建一个子类来实现,并且新增SetInstance来替换掉单例。

使用裸指针报了很多内存问题,所以我改为使用智能指针。

#include <gtest/gtest.h>
#include <gmock/gmock.h>

using ::testing::_;
using ::testing::Return;

template <typename T>
class Foo
{
private:
    static std::unique_ptr<Foo> instance; // 不使用裸指针,防止内存问题

public:
    static Foo &GetInstance()
    {
        if (!instance)
        {
            instance = std::make_unique<Foo>();
        }
        return *instance;
    }
    static void SetInstance(std::unique_ptr<Foo> newInstance)
    {
        instance = std::move(newInstance);
    }
    virtual T bar(const T &key) // 不能为纯虚函数
    {
        return key;
    }
    Foo() = default;  // 构造和析构函数都要是 Public
    virtual ~Foo() = default; // 不加virtual会报 leaked mock
    Foo(const Foo &) = delete;
    Foo &operator=(const Foo &) = delete;
};

template <typename T>
std::unique_ptr<Foo<T>> Foo<T>::instance = nullptr;

template <typename T>
class MockFoo : public Foo<T>
{
public:
    MOCK_METHOD(T, bar, (const T &), (override));
};

class fooTest : public ::testing::Test
{
protected:
    void SetUp() override
    {
    }
    void TearDown() override
    {
    }
};

TEST_F(fooTest, fooTest1)
{
    std::unique_ptr<MockFoo<int>> pt = std::make_unique<MockFoo<int>>();
    EXPECT_CALL(*pt, bar(_)).WillOnce(Return(42)); // 不能放下一行的后面,所有权已经移走了
    Foo<int>::SetInstance(std::move(pt));
    EXPECT_EQ(Foo<int>::GetInstance().bar(1), 42);
}

TEST_F(fooTest, fooTest2)
{
    std::unique_ptr<MockFoo<int>> pt = std::make_unique<MockFoo<int>>();
    EXPECT_CALL(*pt, bar(_)).WillOnce(Return(43));
    Foo<int>::SetInstance(std::move(pt));
    EXPECT_EQ(Foo<int>::GetInstance().bar(2), 43);
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

如果智能指针还是不过,那就用裸指针吧:

#include <gtest/gtest.h>
#include <gmock/gmock.h>

using ::testing::_;
using ::testing::Return;

template <typename T>
class Foo
{
private:
    static Foo* instance;

public:
    static Foo &GetInstance()
    {
        if (!instance)
        {
            instance = new Foo();
        }
        return *instance;
    }
    static void SetInstance(Foo* newInstance)
    {
        delete instance;
        instance = newInstance;
    }
    static void Release()
    {
        instance = nullptr;
    }
    virtual T bar(const T &key) // 不能为纯虚函数
    {
        return key;
    }
    Foo() = default;  // 构造和析构函数都要是 Public
    virtual ~Foo() = default; // 不加virtual会报 leaked mock
    Foo(const Foo &) = delete;
    Foo &operator=(const Foo &) = delete;
};

template <typename T>
Foo<T>* Foo<T>::instance = nullptr;

template <typename T>
class MockFoo : public Foo<T>
{
public:
    MOCK_METHOD(T, bar, (const T &), (override));
};

class fooTest : public ::testing::Test
{
protected:
    void SetUp() override
    {
        pt = new MockFoo<int>();
        MockFoo<int>::SetInstance(pt);
    }
    void TearDown() override
    {
        MockFoo<int>::Release();
        delete pt;
    }
    MockFoo *pt = nullptr;
};

TEST_F(fooTest, fooTest1)
{
    EXPECT_CALL(*pt, bar(_)).WillOnce(Return(42));
    EXPECT_EQ(Foo<int>::GetInstance().bar(1), 42);
}

TEST_F(fooTest, fooTest2)
{
    EXPECT_CALL(*pt, bar(_)).WillOnce(Return(43));
    EXPECT_EQ(Foo<int>::GetInstance().bar(2), 43);
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
posted @ 2025-12-24 21:25  mariocanfly  阅读(16)  评论(0)    收藏  举报