接口(宏)简单介绍

  • SMOCK StubMock类的单例对象
  • V_ADDR 获取类虚拟函数地址
  • O_ADDR 获取重载函数地址(只支持类成员函数)
  • NF_SMOCK 函数打桩
  • F_SMOCK 函数打桩,会去调用NF_SMOCK,调用时默认第一个参数为0
  • SMOCK_CLEAR 清除所有打桩函数

整体的简单介绍

  • StubMock是继承Stub的一个单例类,SMOCK宏是获取单例对象的简便方式,因为是继承Stub并且一些功能限制,因此需要修改Stub源代码:
  • private 修改成protected
  • 将虚构函数中的清除打桩函数操作单独变成一个函数,SMOCK_CLEAR宏将会调用该函数。
  • 因为使用仍然是Stub的打桩,因此整体需要的两个东西不会改变,即被打桩函数的地址和打桩函数的地址,StubMock优化了打桩函数的地址,它提供了更友好的交互方式:
  • lambda表达式
  • gmock的action类
  • 关于为什么使用NF_SMOCK为什么第一次参数需要带一个编号,因为实现问题(不想使用__COUNTER__宏),对于每一种函数类型同一时刻只能有一个被打桩,因此需要添加不同的编号来做到打桩一定成功。

推荐每一个打桩都用不同的编号,否则会给自己精神压力,因为会需要一直查看是否有相同类型的函数被打桩。

使用方式

静态函数打桩

// unistd.h
extern ssize_t read (int __fd, void *__buf, size_t __nbytes) __wur;
// string.h
extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));

using namespace testing;

class CLS {
public:
  static void s1() {}
};

TEST {
  // use lambda
  NF_SMOCK(0, read, [] { return 0; }); // have return type
  NF_SMOCK(1, read, [] {}); // no return type
  NF_SMOCK(2, ADDR(CLS, s1), [] {})); // class static function
  
  // use gmock action
  NF_SMOCK(0, read, Return(0)); // have return type
  NF_SMOCK(1, read, Return()); // no return type
  NF_SMOCK(2, ADDR(CLS, s1), Return()); // class static function
  
  // do something
  
  SMOCK_CLEAR; // clear
}

类成员函数打桩

using namespace testing;

class CLS {
  int cfn(int x) const { return 0; }
}

TEST {
  // use lambda
  NF_SMOCK(0, ADDR(CLS, cfn), [] { return 1; }));
  
  // use gmock action
  NF_SMOCK(0, ADDR(CLS, cfn), Return(1));
  
  // do something
  
  SMOCK_CLEAR; // clear
}

虚函数打桩

using namespace testing;

class CLS {
  virtual int vir_fun() const { return 0;}
}

TEST {
  // use lambda
  NF_SMOCK(0, V_ADDR(CLS, cfn), [] { return 1; }));
  
  // use gmock action
  NF_SMOCK(0, V_ADDR(CLS, cfn), Return(1));
  
  // do something
  
  SMOCK_CLEAR; // clear
}

重载函数打桩

O_ADDR(arg1, arg2, arg3, arg4, arg5)

  • arg1 类名
  • arg2 函数名
  • arg3 返回类型
  • arg4 参数列表
  • arg5 类函数描述符列表(const, …)
class CLS {
  int fun() const { return 0;}
  int fun(double) const { return 0;}
};

TEST(a, b) {
  // use lambda
  NF_SMOCK(0, O_ADDR(CLS, fun, int, (), (const)), [] { return 1; });
  NF_SMOCK(1, O_ADDR(CLS, fun, int, (double), (const)), [] { return 2; });
  
  // use gmock action
  NF_SMOCK(0, O_ADDR(CLS, fun, int, (), (const)), Return(1));
  NF_SMOCK(1, O_ADDR(CLS, fun, int, (double), (const)), Return(2));
  
  // do something
  
  SMOCK_CLEAR; // clear
}

lambda表达式使用的场景

lambda一般用于逻辑不单一的场景,如:

// unistd.h
extern ssize_t read (int __fd, void *__buf, size_t __nbytes) __wur;

TEST {
  NF_SMOCK(0, read, []{
    static int cnt = 0;
    cnt++;
    if (cnt == 1) return 0;
    return -1;
  });
  
  // do something
  
  SMOCK_CLEAR; // clear
}

gmock action

gmock action中最常用是就是Return函数,一般分为两种:

  1. Return(), 不加返回值用于匹配返回类型为void的打桩函数
  2. Return(x), 用于匹配返回类型与x类型相同的打桩函数

代码

橘色的喵/custom_gtest_stub