0


玩转单元测试之cppmockfree

引言

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

快速入门

1. mock样例

1.1 全局函数
// gloabal functionintg_func(int a,int b){return a + b;}
#include"gtest/gtest.h"#include"gmock/gmock.h"#include"cpp_free_mock.h"#include<string>usingnamespace::testing;usingnamespace::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 成员函数
classAdder{public:intadd(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 functionclassPrinter{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 functionclassOverloadFunc{public:intfoo(){return0;}intfoo(int a){return a;}};
TEST(TestCppMockFree, CaseOverloadFunction){
    OverloadFunc overload_func;typedefint(OverloadFunc::*FuncType0)();typedefint(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 classtemplate<classT>classAdderT{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 functiontypedefint(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 functionauto 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

4. 补充

4.1 支持虚函数mock

当前该框架不支持类的虚函数的mock,因此做了一些改进以支持对虚函数的mock。

classClassA{public:virtual~ClassA(){}virtualintfunc(int num){return num;}};TEST(TestCppMockFree, CaseVirtualFunc){
    ClassA a;// typedef int (ClassA::*FuncT)(int); // 成员函数的函数类型typedefint(*RealFuncT)(ClassA*,int);// 等价于成员函数的普通函数类型// 单独声明一个变量用于避免pmf-conversions warnnigauto func =&ClassA::func;// 获取指向虚函数func的实际函数指针// &ClassA::func获取的是虚函数func相对于虚函数表的偏移量+1的值// 如此处func相对虚函数表的偏移值是8(64位系统),所以&ClassA::func的值是9
    RealFuncT real_func =(RealFuncT)OBTAIN_REAL_FUNC(&a,(intptr_t&)func);auto mock =MOCKER(real_func);EXPECT_CALL(*mock,MOCK_FUNCTION(_, _)).WillRepeatedly(Return(123456));EXPECT_EQ(123456, a.func(123));

    mock->RestoreToReal();EXPECT_EQ(123, a.func(123));}

其中OBTAIN_REAL_FUNC函数如下:

/// 在cpp_free_mock.h中添加如下宏:#defineOBTAIN_REAL_FUNC(obj_ptr, member_func)\obtainRealFunc(obj_ptr,reinterpret_cast<constvoid*>(member_func)/// 在cpp11/impl.h中添加如下函数:inlinevoid*obtainRealFunc(constvoid* obj_ptr,constvoid* member_func){
  intptr_t func_offset =reinterpret_cast<intptr_t>(member_func);
  intptr_t func_addr =*reinterpret_cast<intptr_t*>(*reinterpret_cast<const intptr_t*>(obj_ptr)+ func_offset -1);returnreinterpret_cast<void*>(func_addr);}

上述获取虚函数地址的原理可以参考这篇文章:C++中如何获取虚表和虚函数的地址

总结

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

本文转载自: https://blog.csdn.net/weixin_43519984/article/details/132366596
版权归原作者 Black.Spider 所有, 如有侵权,请联系我们删除。

“玩转单元测试之cppmockfree”的评论:

还没有评论