cmocka入门教程

文章目录

    • 摘要
    • 前言
    • 什么是mock
    • mock示例
      • cmocka安装
      • 使用mock function替换subfunction
      • 控制mock function的输入和输出

摘要

本文介绍cmocka中,mock的使用。


前言

在这之前,需要了解最基本的cmocka使用。如果之前有gtest的编程经验,掌握cmocka的简单使用非常容易。这里有份入门文档,我不再赘述:使用 cmocka 进行单元测试 | 前尘逐梦

单元测试框架的基本逻辑是:

  • 测试内容相似的,放在一个组。这个通常称为Test Fixtures(Using the Same Data Configuration for Multiple Tests)。
  • 相同数据的准备和清除动作,通常由setup/teardown这两组函数来执行。
  • 一个具体的单元测试中,通常使用断言(Assertions),来决定单元测试是否通过。
  • 然后就是mock,这个有点高级,也是本文介绍的内容。

什么是mock

cmocka 是一个优雅的 C 单元测试框架,支持mock objects。它只需要标准的 C 库,可以在一系列计算平台(包括嵌入式)和不同的编译器上工作。

什么是mock呢?我问了下chatgpt, 它告诉我这些内容:

在单元测试中,Mock是一种测试技术,用于模拟(或称为替代)系统的组件或依赖项。当编写单元测试时,我们通常希望专注于测试当前正在编写的代码单元,而不是依赖于其他组件或外部系统。为了实现这一目标,我们可以使用Mock对象来替代这些依赖项,以便我们能够控制测试环境并验证代码的行为。使用Mock的主要目的是:

  1. 模拟外部依赖项:例如,当测试一个函数,它依赖于数据库或网络服务时,我们可以使用Mock对象代替实际的数据库或网络服务,以确保测试的独立性和可控性。
  2. 简化测试环境:有时,某些依赖项可能很难配置或设置,使用Mock对象可以避免设置这些复杂的依赖项,从而简化测试环境的搭建。
  3. 控制测试场景:Mock对象可以模拟各种情况和条件,使测试更全面和灵活。

嗯,说的挺好。但如果是第一次接触mock,还是会不明白。因为上面只是告诉了我们mock的好处/必要性,但是该怎么实现呢?

我们通过图片来说明,图片来自:Unit testing and mocking wi nd mocking with cmocka

当我们想对一个函数(function)进行单元测试时,但是这个函数内部调用了子函数(subfunction)。函数的结果由子函数决定,但是子函数的返回值是变化的/依赖外部数据库等。此时,想给函数添加单元测试,殊为不易。单元测试-函数-子函数的调用链如下所示:

在这里插入图片描述

此时,如果我们能在调用函数时,使用我们自定义的函数(mock function)替换掉子函数。并且,如果我们可以控制这个mock function的输入和输出,并将mock funciton的输出喂给函数,那么我们就可以给函数添加单元测试了。mock过程如下图所示:

在这里插入图片描述


mock示例

书接上文。mock的核心有两点:(1)单元测试中,使用mock function替换subfunction。(2)单元测试中,可以控制mock function的输入和输出

talk is cheap, show me your code.

本文的示例代码来自:example/mock/uptime · master · cmocka / cmocka · GitLab


cmocka安装

首先我们需要先下载和编译上面的示例代码。

# 为了查看示例更加方便,需要下载源码编译
## 具体如何编译,查看里面的README.md和INSTALL.md
wget https://cmocka.org/files/1.1/cmocka-1.1.7.tar.xz
tar -xvf cmocka-1.1.7.tar.xz
cd cmocka-1.1.7.tar.xz
mkdir build && cd build
cmake .. -DBUILD_SHARED_LIBS=OFF
make

# 包管理器方式安装 
## alamlinux8上,这个包中只包含动态库。如果需要静态链接,只好上面源码的方式集成
dnf install libcmocka-devel

使用mock function替换subfunction

这一步需要在链接(ld)的时候做。编译链接的选项中添加-Wl,--wrap=uptime。可以看到示例的CMakeLists.txt中有这样的内容:

set_property(TARGET
                 test_uptime
             PROPERTY
                 LINK_FLAGS
                    "${DEFAULT_LINK_FLAGS} -Wl,--wrap=uptime")

-Wl告诉 GCC 将后面的选项传递给链接器 ld。关于--wrap选项,我在gcc手册中没有找到。这个选项在man ld中。

Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to “__wrap_symbol”. Any undefined reference to “__real_symbol” will be resolved to symbol.
Only undefined references are replaced by the linker. So, translation unit internal references to symbol are not resolved to “__wrap_symbol”.

啥意思呢?要看明白上面的意思,还得先明白啥叫translation unit。可参考:c++ faq - What is a “translation unit” in C++? - Stack Overflow

translation unit定义:是C++中编译的基本单元。它由单个源文件的内容组成,加上它直接或间接包含的任何头文件的内容,减去使用条件预处理语句忽略的那些行。

以上一节的图为例,它的意思是,当function和subfunction位于不同文件时,使用--warp选项后,function实际会去链接__wrap_subfunction

注意,function和subfunction不能在同一个translation unit,否则--warp选项无效(我踩过这个坑了)。相关内容可见:c - GCC’s linker --wrap will not wrap over static library function - Stack Overflow、 wrapper - How to wrap existing function in C - Stack Overflow

本节具体的代码示例,可见上面的链接。(这里有篇博客,也有示例代码,但是它的代码结构不好: GCC中通过–wrap选项使用包装函数-CSDN博客)


控制mock function的输入和输出

为了说明方便,我拷贝下示例代码,完整的代码见链接example/mock/uptime · master · cmocka / cmocka · GitLab。

由于链接选项中,设置了-Wl,--wrap=uptime。所以当calc_uptime()中调用uptime()时,将会调用__wrap_uptime()。链接过程帮我们做了函数替换。此时需要使用CMocka API - Mock Objects控制__wrap_uptime()的输入输出了。

will_return(): Store a value to be returned by mock() later。

test_calc_uptime_minutes调用了两个will_return(),给__wrap_uptime放入了两个值。__wrap_uptime通过两次mock_type取出。(内部的原理不清楚,但是使用还是蛮简单的嘛。)

int __wrap_uptime(const char *uptime_path,
                  double *uptime_secs,
                  double *idle_secs)
{
    double up;
    double idle;

    /* Verify the passed value of the argument is correct */
    check_expected_ptr(uptime_path);

    /* Assign the return values */
    up = mock_type(double);
    idle = mock_type(double);

    if (uptime_secs != NULL) {
        *uptime_secs = up;
    }
    if (idle_secs != NULL) {
        *idle_secs = idle;
    }

    return (int)up;
}

static void test_calc_uptime_minutes(void **state)
{
    char *uptime_str = NULL;

    UNUSED(state);

    /* Make sure the passed 'in' argument is correct */
    expect_string(__wrap_uptime, uptime_path, "/proc/uptime");

    /* We tell the uptime function what values it should return */
    will_return(__wrap_uptime, 508.16);
    will_return(__wrap_uptime, 72.23);

    /* We call the function like we would do it normally */
    uptime_str = calc_uptime();

    /* Now lets check if the result is what we expect it to be */
    assert_non_null(uptime_str);
    assert_string_equal(uptime_str, "up 8 minutes");

    free(uptime_str);
}

这里,我再顺道介绍下expect_stringcheck_expected_ptr。这两个函数在cmocka API - Checking Parameters中。

test_calc_uptime_minutes“大吼一声”,我要在calc_uptime调用__wrap_uptime时,检查下uptime_path这个变量是不是"/proc/uptime"。test_calc_uptime_minutes在执行前设置了期望;__wrap_uptime在执行时,验证期望。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/532085.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯 迷宫(bfs)

0迷宫 - 蓝桥云课 (lanqiao.cn) 思路 : 最后一定要倒数输出路径,因为从前面输出你会找不到下一个到底是谁,bfs过程是找最小路径,最后输出是去找方向,但是此题作为一个填空题,我直接手写(开玩笑…

对于Redis,如何根据业务需求配置是否允许远程访问?

1、centos8 Redis安装的配置文件目录在哪里? 在 CentOS 8 中,默认情况下 Redis 的配置文件 redis.conf 通常位于 /etc/ 目录下。确切的完整路径是 /etc/redis.conf。 2、redis如何设置允许远程登录 修改redis.conf文件 # 继承默认注释掉的bind配置 # …

十种mfc140.dll丢失的解决方法,有效解决mfc140.dll丢失的问题

唉,烦人的问题又来了。怎么计算机报错提示mfc140.dll无法启动?这mfc140.dll是何方神圣,竟然连软件程序的正常运行都能影响到?我猜你也被这种困扰搞得头大吧。别着急,下面我会详细分享mfc140.dll丢失时的修复步骤&#…

Android平台RTSP|RTMP播放器如何实现TextureView渲染

技术背景 自2015年我们发布Android平台RTSP、RTMP直播播放模块以来,渲染这块,支持SurfaceView或GlSurfaceView,当然如果开发者需要TextureView渲染,可以把RTSP、RTMP流数据解码回调YUV或RGB数据上来,上层自己渲染。本…

pycharm一直打不开

一直处在下面的页面,没有反应 第一种方案: 以管理员身份运行 cmd.exe;在打开的cmd窗口中,输入 netsh winsock reset ,按回车键;重启电脑;重启后,双击pycharm图标就能打开了&#xf…

阿里淘天一面凉经

电话面,秒挂。 由于答的依托。导致面试官一开始就准备要挂我了。后面问的参考性不大。 总结: 1.自我介绍 2.项目里自己体会比较多的,遇到困难比较大的技术实现。(没复习) 3.项目中什么场景下用到分布式锁&#xf…

提升Terraform工作流程最佳实践

Terraform 是管理基础设施及代码(IaC)最常用的工具之一,它能使我们安全且可预测地对基础设施应用更改。刚开始上手 Terraform 可能会感觉有些不容易,但很快就能对该工具有基本的了解,随之可以开始运行命令、创建和重构…

如何压缩视频?5种超简单的方法!

用视频来记录生活和重要信息变得越来越广泛,比如用手机拍摄美好瞬间、对线上会议或课堂的内容进行视频录制、保存各种精彩的电影文件、社交媒体上分享美好生活,但是由于视频本身包含的信息很多以及拍摄设备的进步,文件越来越大,占…

08 Php学习:iff语句、Switch语句

PHP 条件语句 当您编写代码时,您常常需要为不同的判断执行不同的动作。您可以在代码中使用条件语句来完成此任务。 在 PHP 中,提供了下列条件语句: if 语句 - 在条件成立时执行代码 if…else 语句 - 在条件成立时执行一块代码,…

FreeRTOS任务切换学习

FreeRTOS任务切换学习 所谓任务切换,就是CPU寄存器的切换。假设当由任务A切换到任务B时,主要分为两步: 1:需暂停任务A的执行,并将此时任务A的寄存器保存到任务堆栈,这个过程叫做保存现场; 2&am…

【STL】list

目录 1. list的使用 1.1 list的构造 1.2 list iterator的使用 1.3 list capacity 1.4 list element access 1.5 list modifiers 1.6 list的迭代器失效 2. list的模拟实现 3. list与vector的对比 1. list的使用 1.1 list的构造 1.2 list iterator的使用 1. begin与end为…

雨污管网开挖深度的计算

一般的管网工程都有纵断面设计图,结合纵断面里的 管内底埋深-管厚度(直径0.6管厚0.06,直径0.8承插管直径0.08厚) - 砂砾石基础一般0.15厚 - 路面结构层厚度就是沟槽开挖深度了,是不是很简单。 管内底埋深其实就是管内流水面到设计路面顶的高…

PyCharm+PyQt5配置方法

一、前言 PyQt5PyQt5是一套Python绑定Digia QT5应用的框架。Qt库是最强大的GUI库之一PyQt5-toolsPyQt5中没有提供常用的Qt工具,比如图形界面开发工具Qt Designer,PyQt5-tools中包含了一系列常用工具Qt Designer可以通过Qt Designer来编写UI界面&#xf…

Docker快速上手及常用命令速查

Docker快速上手 安装 在ubuntu上安装docker: sudo apt-get install docker docker -v #查看版本在centos7上安装docker:(docker在YUM源的Extras仓库中) yum install docker systemctl start dockerdocker常用命令速查 #查看docker信息 docker info #查看本地镜…

网络基础三——其他周边问题

3.1ARP原理 ​ ARP不是一个单纯的数据链路层的协议,而是一个介于数据链路层和网络层之间的协议; ​ 以广播的形式(主机号填成全1)构建Mac帧,发送ARP请求包,告诉所有在局域网的主机我的IP地址和Mac帧,与目的IP相同的主…

[lesson16]类的真正形态

类的真正形态 类的关键字 struct在C语言中以及有了自己的含义,必须继续兼容 在C中提供了新的关键字class用于类的定义 class和struct的用法是完全相同的 在用struct定义类时,所有成员的默认访问级别为public 在用class定义类时,所有成员…

Leetcode算法训练日记 | day22

一、二叉搜索树的最近公共祖先 1.题目 Leetcode:第 235 题 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足…

liunx环境变量学习总结

环境变量 在操作系统中,环境变量是一种特殊的变量,它们为运行的进程提供全局配置信息和系统环境设定。本文将介绍如何自定义、删除环境变量,特别是对重要环境变量PATH的管理和定制,以及与环境变量相关的函数使用。 自定义环境变…

【复现】用友NC-Cloud文件上传漏洞_70

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一: 四.修复建议: 五. 搜索语法: 六.免责声明 一.概述 用友NC Cloud大型企业数字化平台,深度应用新一代数字智能技术,完全基于云原生架构,打造开放、…

MySQL进阶之(七)EXPLAIN 详解

七、EXPLAIN 详解 7.1 查询性能那些事7.1.1 查看系统性能参数7.1.2 统计 SQL 的查询成本7.1.3 定位执行慢的 SQL:慢查询日志01、开启慢查询日志参数02、关闭慢查询日志03、删除慢查询日志 7.1.4 查看 SQL 执行成本:SHOW PROFILE 7.2 EXPLAIN 语句输出中各…