单元测试googletest gmock

一:Mock C code


对于c code,gcc 提供了编译链接选项:-Wl,-wrap
比如gcc编译时加入链接选项 -Wl,--wrap,malloc,
那么函数调用malloc的时候会调用自定义的__wrap_malloc,而原来的malloc会以__real_malloc进行调用。
所以程序需要定义一个__wrap_malloc,比如:

void* __wrap_malloc(size_t size) // 定义__wrap_malloc
{
    printf("__wrap_malloc called, size:%zd\n", size); // log输出
    return __real_malloc(size); // 通过__real_malloc调用真正的malloc
}

二:Mock C++ code (Google Mock/Gmock)

          
1) google mock介绍,以及EXPECT_CALL vs ON_CALL
https://slidedeck.io/DonaldWhyte/gmock-presentation

2) Mock函数设置函数参数
SetArgReferee<N>(value)
SetArgPointee<N>(value)
"Assign value to the variable referenced by the N-th (0-based) argument" and
"Assign value to the variable pointed by the N-th (0-based) argument" respectively.

比如:
ON_CALL(mock, Sign(Eq(0), _))
  .WillByDefault(DoAll(SetArgPointee<1>("set argument1"), Return(0)));
 
3) using testing
using testing::_;
using testing::Return;
using testing::NiceMock;
using testing::SetArgPointee;
using testing::DoAll;

4) 示例
Gmock的前提是对于被Mock的函数所在的类,其基类提供的函数是虚函数,
这样Mock类可以继承该基类并提供Mock函数实现。比如基类:

class MyInterfaceBase
{
public:

    virtual bool my_func(char* param1, int param2, bool *param3) = 0;
    virtual bool my_func_variable_param(char* param1, bool param2 = false) = 0;
}

Mock类:

class My_Mock: public MyInterfaceBase
{
    MOCK_METHOD3(my_func, bool(char* param1, int param2, bool *param3));
    MOCK_METHOD2(my_func_variable_param_impl, bool(char* param1, bool param2));
    
    bool my_func_variable_param(char* param1, bool param2 = false);
}

inline bool
My_Mock::my_func_variable_param(char* param1, bool param2)
{
    return my_func_variable_param_impl(char* param1, bool param2);
}


UT测试:

注意,具体测试中需要有办法将待mock的类XXX 比如:

class XXX: public MyInterfaceBase

替换成My_Mock,比如XXX是其他某个类的成员变量 比如

class YYY

{

......

MyInterfaceBase xxx;

......

}

同时又提供了Set函数来set变量,那么可以用来替换成My_Mock.

My_Mock *mock_ptr = new NiceMock<My_Mock>();//NiceMock可以防止warning

ON_CALL(*mock_ptr, my_func(_, _, _)).WillByDefault(Return(true));

或者,如果想设置函数参数,比如将第三个参数bool *param3指向的值设置为true:
ON_CALL(*mock_ptr, my_func(_, _, _)).WillByDefault(
                    DoAll(SetArgPointee<2>(true), Return(true)));

              
5) 可变参数
gmock需要指定参数个数,比如MOCK_METHOD2固定2个函数参数,如果有可变参数,需要变通。
比如基类函数my_func_variable_param是可变参数,那么对于Mock类My_Mock来说,需要将
my_func_variable_param函数代理给一个新的固定参数函数,比如my_func_variable_param_impl,
然后通过这个代理函数实现ON_CALL/EXPECT_CALL设置函数返回值。
比如:
ON_CALL(*mock_ptr, my_func_variable_param_impl(_, _,)).WillByDefault(Return(true));

对于被测试函数,其调用my_func_variable_param可以传1个(另外一个采用默认参数)或者2个参数。

三: Mock global function

比如需要mock C/C++的global function, 可以参考下面的方式进行stub + mock

https://github.com/apriorit/gmock-global

https://github.com/apriorit/gmock-global-sample/blob/master/src/sample/main.cpp

https://www.codeproject.com/Tips/1262469/Gmock-Enhancements-Mocking-Global-Functions-and-Me

https://github.com/coolxv/cpp-stub

如果是mock C++ global function, 最好加上namespace, 以免在其他文件中也做同样的mock造成重复定义,示例:

假设待mock的函数原型为:

int My_func(int i, int j);

 那么,mock写法为:

using namespace testing;

namespace testxxxxx
{
    MOCK_GLOBAL_FUNC2(MOCK_My_func, int(int i, int j);
}
          
		  
using namespace testxxxxx;

在具体的case里面进行stub替换:

EXPECT_GLOBAL_CALL(MOCK_My_func, MOCK_My_func(_,_)).WillRepeatedly(Return(0));
Stub stub;
stub.set(My_func, MOCK_My_func);

这里是具体的单元测试......

stub.reset(My_func);

一个特殊情况是针对C++的函数重载, 需要采用函数指针来解决:

比如重载的函数原型为:

int My_func(int i);
int My_func(int i, int j);

   如果想mock两个参数的:

EXPECT_GLOBAL_CALL(MOCK_My_func, MOCK_My_func(_,_)).WillRepeatedly(Return(0));
int(*myFunc)(int i, int j) = &My_func;
Stub stub;
stub.set(myFunc, MOCK_My_func);

这里是具体的单元测试......

stub.reset(myFunc);

  其他高级用法与gmock类似,比如:

EXPECT_GLOBAL_CALL(MOCK_My_func, MOCK_My_func(_,_)).WillRepeatedly(DoAll(SetArgReferee<1>(1), Return(0)));


参考:                    
https://stackoverflow.com/questions/32911356/google-mock-functions-changing-value-of-parameter
https://stackoverflow.com/questions/13933475/gmock-setting-default-actions-on-call-vs-expect-call

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Google Test单元测试,你可以在C++项目中使用Google Test框架来编写和运行单元测试。 首先,你需要在项目中包含Google Test库。你可以从Google Test的官方GitHub仓库下载最新版本的源代码,并将其添加到你的项目中。 在编写单元测试之前,你需要创建一个测试文件。这个文件应该包含一个或多个测试用例,每个测试用例都是一个函数。你可以使用Google Test提供的宏来定义和运行测试用例。 一个简单的示例代码如下: ```c++ #include <gtest/gtest.h> // 定义一个测试用例 TEST(ExampleTest, Addition) { int a = 2; int b = 3; int result = a + b; EXPECT_EQ(result, 5); } // 定义另一个测试用例 TEST(ExampleTest, Subtraction) { int a = 5; int b = 3; int result = a - b; EXPECT_EQ(result, 2); } int main(int argc, char** argv) { // 初始化 Google Test 框架 ::testing::InitGoogleTest(&argc, argv); // 运行所有的测试用例 return RUN_ALL_TESTS(); } ``` 在这个例子中,我们定义了两个测试用例:Addition和Subtraction。每个测试用例都包含一些断言,用于验证预期结果和实际结果是否相等。在main函数中,我们初始化Google Test框架并运行所有的测试用例。 要编译和运行这个测试文件,你需要将Google Test库链接到你的项目中。具体的编译和链接过程可能因你使用的开发环境而有所不同。 当你运行这个测试文件时,Google Test将会执行所有的测试用例,并输出测试结果。如果所有的断言都通过了,测试将会被标记为通过;否则,测试将会被标记为失败,并显示详细的错误信息。 这只是一个简单的示例,Google Test还提供了很多其他的功能和特性,例如测试夹具、参数化测试、测试报告等。你可以查阅Google Test的官方文档以获取更多信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值