# emock
**Repository Path**: pytf/emock
## Basic Information
- **Project Name**: emock
- **Description**: No description available
- **Primary Language**: C++
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2025-04-23
- **Last Updated**: 2025-04-23
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
[English README](./README_en.md)
# EMOCK [](https://github.com/ez8-co/emock/blob/master/LICENSE) [](https://orca-zhang.semaphoreci.com/projects/emock) [](https://ci.appveyor.com/project/orca-zhang/emock)
- EMOCK是基于mockcpp核心改进的下一代C/C++跨平台mock库
- **【使用简单】** 学习成本低,仅一个宏
- **【没有依赖】** 除了STL和系统库函数
- **【跨平台】** 支持主流32/64位系统(\*nix、Windows、MacOS)
- **【完全支持】** 支持mock所有类型的函数
- **【非侵入设计】** 不需要调整任何待测代码
## 正在开发
- :cow: 类似反射功能支持,无需声明即可mock(支持不可见的静态全局函数和动态库内部函数)
- linux下改用dwarf实现
- 支持C语言声明的函数
- 支持mock带有异常约束的函数
- 默认单元测试框架改用gtest
- 缺失的caller匹配功能
## 最新支持
- 统一的`EMOCK`宏(测试虚函数,不再需要用户添加控制反转支持)
- 支持mock可变参数函数,例如:`int test(int a, ...)`
- 支持mock重载的成员函数(Windows系统)
- 解决老的获取成员函数方法会有警告问题(Linux系统)
- 使用蹦床使得this指针可见(Windows系统)
- :clap: 使用短跳+蹦床的方法解决x64下非期望覆盖较小函数的问题
## 特性矩阵
#### 下面是和一些主流mock库的对比(如有错误,不吝指正)
|
平台 |
成员函数 |
普通函数 |
杂项 |
库 |
Linux |
Win |
Mac |
虚函数 |
普通 |
静态 |
全局 |
变参 |
模板 |
无需修改 |
EMOCK |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
CppUMock |
:white_check_mark: |
:white_check_mark: |
:x: |
:white_check_mark: |
:x: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:x:[0] |
mockcpp |
:white_check_mark: |
:white_check_mark: |
:x: |
:white_check_mark: |
:x: |
:white_check_mark: |
:white_check_mark: |
:x: |
:white_check_mark: |
:x:[1] |
googlemock |
:white_check_mark: |
:white_check_mark: |
:x: |
:white_check_mark: |
:x: |
:x: |
:x: |
:x: |
:x: |
:x:[2] |
mockitopp |
:white_check_mark: |
:white_check_mark: |
:x: |
:white_check_mark: |
:x: |
:x: |
:x: |
:x: |
:x: |
:x:[1] |
C-Mock |
:white_check_mark: |
:x: |
:x: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:x: |
:x: |
:x:[1] |
CppFreeMock |
:white_check_mark: |
:x: |
:x: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:white_check_mark: |
:x:[1] |
- 注:
- [0]: 需要IoC接口,派生并实现待测类的虚成员函数
- [1]: 需要定义接口(只有纯虚成员函数),不支持混合类(同时包含虚成员函数和普通成员函数的类)
- [2]: 需要IoC接口,需要声明含有待测虚成员函数的派生类(相同参数列表和返回类型)
- [0][1][2]: 无法测试类内嵌对象或者引用
#### 与使用API HOOK技术的库对比
库 |
跳转安全 |
this指针可见[Windows] |
备注 |
EMOCK |
:white_check_mark: |
:white_check_mark: |
使用蹦床将远跳变为短跳 |
mockcpp |
:x: |
:x: |
x64下直接使用14字节的远跳 |
CppFreeMock |
:x: |
:x: |
x64下直接使用14字节的远跳 |
- EMOCK理论上也支持UNIX, Android和iOS等\*nix系统,但可能需要少量改动
## 快速概览
#### 全局函数
```cpp
// 待测函数
int foobar(int x) {
return x;
}
// 测试时,像下面这样就可以mock
EMOCK(foobar)
.stubs()
.with(any()) // 约束匹配任意输入
.will(returnValue(1)); // 调用时返回1
// 调用会返回1
ASSERT_EQ(foobar(0), 1);
```
#### 成员函数
```cpp
// 待测成员函数
class Foo
{
public:
void bar1(int);
virtual void bar2(double);
static int bar3();
};
////////////////////////////////////
// 指定调用的mock函数
void EMOCK_API mock_bar1(Foo* obj, int) {
// ...
}
void EMOCK_API mock_bar2(Foo* obj, double) {
// ...
}
// 测试时,像下面这样就可以mock
EMOCK(&Foo::bar1)
.stubs()
.will(invoke(mock_bar1)); // 指定调用自定义的函数而不是指定返回值
EMOCK(&Foo::bar2) // 虚成员函数并不特别
.stubs()
.will(invoke(mock_bar2));
EMOCK(Foo::bar3) // 静态函数类似全局函数,不需要&
.stubs()
.will(returnValue(1));
```
#### 重载函数
```cpp
// 待测重载函数
int foobar(int x) {
return x;
}
double foobar(double x) {
return x;
}
// 重载函数,像下面这样就可以mock
EMOCK((int (*)(int))foobar)
.stubs()
.will(returnValue(1));
EMOCK(static_cast(foobar))
.stubs()
.will(returnValue(1.0));
// 待测重载成员函数
class Foo
{
public:
void bar(int);
void bar(double);
};
// 重载的成员函数,像下面这样就可以mock
EMOCK((void (Foo::*)(int))&Foo::bar)
.expects(once()); // 只会调用一次
EMOCK(static_cast(&Foo::bar))
.expects(never()); // 不会被调用
```
## 实验功能(根据函数签名式mock)
```cpp
EMOCK("foo::bar")
.stubs()
.will(returnValue(1));
```
- 设计参考 [MSDN - SymEnumSymbols](https://docs.microsoft.com/zh-cn/windows/win32/api/dbghelp/nf-dbghelp-symenumsymbols?redirectedfrom=MSDN)
- 使用规范:`[[__cdecl|__stdcall|__thiscall]#]|[!] [{}] [::] [::] [()] [@]`
- 支持通配符,`*` 代表任意数量个字符,`?` 代表单个字符
- `@` 后面为库名,`#` 前为调用约定,其中用`!`是`__stdcall#`的缩写, `{int}`代表返回值类型为`int`
- 例如:`!{int}*::foo::bar(double)@x??`代表返回值为`int`类型,调用约定为`__stdcall`的方法`foo::bar`,命名空间任意匹配,库名`x??`代表`x`开头,且为三个字符
## 使用手册
- [访问wiki学习如何使用EMOCK(建设中,可以参考网上mockcpp的教程)](https://github.com/ez8-co/emock/wiki)
## 衷心感谢
- EMOCK是基于mockcpp完善而来的
- 向mockcpp的作者和主要贡献者致敬:
- [Darwin Yuan: darwin.yuan@gmail.com](https://github.com/godsme)
- [Chen Guodong: sinojelly@gmail.com](https://github.com/sinojelly)
- 最原始版本从[mockcpp@bitbucket](https://bitbucket.org/godsme/mockcpp)导入
## 已知问题
- 和`valgrind`一起使用
- 请添加`--smc-check=all`选项禁用缓存来防止动态修改机器码(API HOOK技术)部分失效导致不可预期的错误
- 因为`valgrind`的特殊处理,暂时无法mock系统调用相关函数 (例如 `gettimeofday`)
## 写在最后
- 欢迎使用EMOCK,并期待您的反馈
## 请我喝一杯咖啡