玩转单元测试之cppmockfree

引言

前文我们已经讲解了gmock的基本语法,但是gmock只能mock虚函数,如果要mock非虚成员函数、静态成员函数、全局函数、重载函数、模板函数以及其他依赖库的函数时,gmock就很难实现。而cppmockfree可以支持这些函数的mock。

快速入门

1. mock样例

1.1 全局函数

// gloabal function
int g_func(int a, int b)
{
    return a + b;
}
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "cpp_free_mock.h"
#include 

using namespace ::testing;
using namespace ::CppFreeMock;

namespace {
TEST(TestCppMockFree, CaseGlobalFunction) 
{
    auto mock = MOCKER(g_func);
    EXPECT_CALL(*mock, MOCK_FUNCTION(_, _))
        .WillOnce(Return(1))
		.WillRepeatedly(Return(2));
    
    EXPECT_EQ(1, g_func(1, 2));
    EXPECT_EQ(2, g_func(12, 2));

    mock->RestoreToReal();
    EXPECT_EQ(14, g_func(12, 2));
}

1.2 成员函数

class Adder {
public:
    int add(int a, int b) const
    {
        return a + b;
    }
};
TEST(TestCppMockFree, CaseStaticMemberFunction) 
{
    auto mock = MOCKER(&Adder::add);
    // 针对类的成员函数,要注意占位符会多出一个,即第一个为this指针
    // 而全局函数或者静态成员函数占位符个数等于实际参数个数
    EXPECT_CALL(*mock, MOCK_FUNCTION(_, _, _))
        .WillRepeatedly(Return(2));
    Adder adder;
    EXPECT_EQ(2, adder.add(1, 2));
    EXPECT_EQ(2, adder.add(12, 2));
    mock->RestoreToReal();
    EXPECT_EQ(14, g_func(12, 2));
}

1.3 静态成员函数

// static member function
class Printer {
public:
    static std::string print(const std::string& str)
    {
        return str;
    }
};
TEST(TestCppMockFree, CaseStaticMemberFunction) 
{
	auto mock = MOCKER(Printer::print);
    EXPECT_CALL(*mock, MOCK_FUNCTION(_))
        .WillRepeatedly(Return(std::string("mocker")));
    
    EXPECT_STREQ("mocker", Printer::print("hello").c_str());

    mock->RestoreToReal();
    EXPECT_STREQ("hello", Printer::print("hello").c_str());
}

1.4 函数重载

// overload function
class OverloadFunc {
public:
    int foo() { return 0; }
    int foo(int a) { return a;}
};
TEST(TestCppMockFree, CaseOverloadFunction) 
{
    OverloadFunc overload_func;
    typedef int (OverloadFunc::*FuncType0)();
    typedef int (OverloadFunc::*FuncType1)(int);
    auto mock0 = MOCKER((FuncType0)&OverloadFunc::foo);
    EXPECT_CALL(*mock0, MOCK_FUNCTION(_))
        .WillRepeatedly(Return(2));
    
    EXPECT_EQ(2, overload_func.foo());

    auto mock1 = MOCKER((FuncType1)&OverloadFunc::foo);
    EXPECT_CALL(*mock1, MOCK_FUNCTION(_,  _))
        .WillRepeatedly(Return(2));

    EXPECT_EQ(2, overload_func.foo(1));

    mock0->RestoreToReal();
    mock1->RestoreToReal();
    EXPECT_EQ(2, overload_func.foo(1));

    mock0->RestoreToReal();
    mock1->RestoreToReal();
    EXPECT_EQ(0, overload_func.foo());
    EXPECT_EQ(1, overload_func.foo(1));
}

1.5 模板类成员函数

// template class
template <class T>
class AdderT {
public:
    T add(T a, T b) { return a + b; }
    T add(T a, T b, T c) { return a + b + c; }
    T adder(T a) { return a; }
};
TEST(TestCppMockFree, CaseTemplateFunction) 
{
    AdderT<int> adder;

    // overload function
    typedef int (AdderT<int>::*FuncType0)(int, int);
 	auto mock0 = MOCKER((FuncType0)&AdderT<int>::add);
    EXPECT_CALL(*mock0, MOCK_FUNCTION(_, _, _))
        .WillRepeatedly(Return(1));

    EXPECT_EQ(1, adder.add(1, 2));
    
    auto mock1 = MOCKER((FuncType1)&AdderT<int>::add);
    EXPECT_CALL(*mock1, MOCK_FUNCTION(_, _, _, _))
        .WillRepeatedly(Return(1));

    EXPECT_EQ(1, adder.add(1, 2, 3));
    
    mock0->RestoreToReal();
    mock1->RestoreToReal();
    EXPECT_EQ(3, adder.add(1, 2));
    EXPECT_EQ(6, adder.add(1, 2, 3));

	// normal function
    auto mock2 = MOCKER(&AdderT<int>::adder);
    EXPECT_CALL(*mock2, MOCK_FUNCTION(_, _))
        .WillRepeatedly(Return(1));
    
    EXPECT_EQ(1, adder.adder(2));

    mock2->RestoreToReal();
    EXPECT_EQ(2, adder.adder(2));
}

1.6 外部库函数

TEST(TestCppMockFree, CaseOtherLibrary)
{
    auto mock = MOCKER(std::atoi);
    EXPECT_CALL(*mock, MOCK_FUNCTION(_))
        .WillRepeatedly(Return(22867));
    
    EXPECT_EQ(22867, std::atoi("123"));

    mock->RestoreToReal();
    EXPECT_EQ(123, std::atoi("123"));
} 

2. 引入cppmockfree

git clone https://github.com/gzc9047/CppFreeMock.git

注意在引入cppmockfree之前请务必引入gtest和gmock。如何引入,在我之前的文章中均有提及。

3. makefile

CXX = g++
CXXFLAGS = -Wall
LIBES = -lgtest -lgtest_main -lpthread
LPATH = -L/tools/googletest/1.11.0/build/lib  # 替换成自己lib路径
HPATH = -I/tools/googletest/1.11.0/googletest/include/ # 替换成自己的include路径
HPATH += -I/xxx/cpp_freemock/ #替换成自己的include路径

UTEST_OBJD = hello_unit_test

hello_unit_test:hello_unit_test.cpp
	${CXX} -o $@ $+ -I ../ ${HPATH} ${CXXFLAGS} ${LIBES} ${LPATH}

clean:
	rm -rf *_unit_test

总结

  • CPPMockFree能够支持几乎所有场景下的接口mock
  • EXPECT_CALL的使用和gmock基本一致,更多的接口如:SaveArg、SetArgReferee等请参考gmock文档

你可能感兴趣的:(生产工具,单元测试,c++)