wordpress+手机站,中小企业网络安全,上海建设网站哪家好,海外网络推广文章目录 摘要前言什么是mockmock示例cmocka安装使用mock function替换subfunction控制mock function的输入和输出 摘要
本文介绍cmocka中#xff0c;mock的使用。 前言
在这之前#xff0c;需要了解最基本的cmocka使用。如果之前有gtest的编程经验#xff0c;掌握cmocka的… 文章目录 摘要前言什么是mockmock示例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的主要目的是 模拟外部依赖项例如当测试一个函数它依赖于数据库或网络服务时我们可以使用Mock对象代替实际的数据库或网络服务以确保测试的独立性和可控性。简化测试环境有时某些依赖项可能很难配置或设置使用Mock对象可以避免设置这些复杂的依赖项从而简化测试环境的搭建。控制测试场景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_LIBSOFF
make# 包管理器方式安装
## alamlinux8上,这个包中只包含动态库。如果需要静态链接只好上面源码的方式集成
dnf install libcmocka-devel使用mock function替换subfunction
这一步需要在链接(ld)的时候做。编译链接的选项中添加-Wl,--wrapuptime。可以看到示例的CMakeLists.txt中有这样的内容
set_property(TARGETtest_uptimePROPERTYLINK_FLAGS${DEFAULT_LINK_FLAGS} -Wl,--wrapuptime)-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,--wrapuptime。所以当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_string和check_expected_ptr。这两个函数在cmocka API - Checking Parameters中。
test_calc_uptime_minutes“大吼一声”我要在calc_uptime调用__wrap_uptime时检查下uptime_path这个变量是不是/proc/uptime。test_calc_uptime_minutes在执行前设置了期望__wrap_uptime在执行时验证期望。