news 2026/4/23 10:47:51

简单理解:什么是CMocka ?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
简单理解:什么是CMocka ?

CMocka 是一款面向 C 语言的轻量级单元测试框架,核心支持Mock 对象模拟,特别适合嵌入式 / SOC 开发中的代码测试。

核心定位

它是从谷歌的 Cmockery 框架继承而来的工具,主打 **“仅依赖标准 C 库”**,能在 Linux、Windows、嵌入式等多平台运行,解决 C 代码(尤其是硬件依赖型代码)的 “单元测试难落地” 问题。

关键功能

  1. Mock 对象模拟可以为依赖的硬件驱动、外部模块创建 “替身函数”:

    • 预设函数的返回值 / 输出参数(比如模拟uart_send()的成功返回,无需真实串口硬件);
    • 校验函数的调用次数、入参、调用顺序(比如确认sensor_read()是否被正确调用)。
  2. 基础测试能力

    • 提供丰富的断言宏(如assert_int_equal验证数值相等);
    • 支持测试夹具(Setup/Teardown),统一管理测试的初始化 / 清理;
    • 检测内存泄漏、缓冲区溢出等问题。
  3. 适配嵌入式场景

    • 仅依赖标准 C 库,可通过交叉编译适配嵌入式平台;
    • 不使用fork()等系统调用,适合资源受限的硬件环境。

典型用法(示例)

比如测试一个依赖 UART 的函数:

#include <cmocka.h> #include "uart.h" // 被依赖的模块 // 被测试函数:调用uart_send发送错误码 void report_error(int code) { uart_send(code); } // Mock替身函数(CMocka自动生成或手动定义) void uart_send(int code) { check_expected(code); // 校验入参是否符合预期 } // 测试用例 void test_report_error(void **state) { (void)state; expect_value(uart_send, code, 100); // 预设期望入参是100 report_error(100); // 执行被测试函数 } // 运行测试 int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_report_error), }; return cmocka_run_group_tests(tests, NULL, NULL); }

优势

  • 轻量无依赖,易集成到嵌入式项目;
  • 同时支持单元测试和接口测试;
  • 输出格式灵活(支持 TAP、JUnit XML,适配持续集成)。

一、环境准备(核心依赖)

CMocka 仅依赖:

  1. C 编译器(gcc/clang/arm-none-eabi-gcc)
  2. 构建工具(cmake 3.10+ 或 make)
  3. CMocka 源码(推荐稳定版 1.1.5)
步骤 1:下载 CMocka 源码
# 方式1:直接下载源码包(推荐) wget https://cmocka.org/files/1.1/cmocka-1.1.5.tar.xz tar -xvf cmocka-1.1.5.tar.xz # 方式2:git克隆(最新版) git clone https://git.cryptomilk.org/projects/cmocka.git

二、编译集成(分 2 种场景)

场景 1:Linux 主机测试(x86/x64,最快验证)
# 1. 进入源码目录,创建编译目录 cd cmocka-1.1.5 mkdir build && cd build # 2. cmake配置(指定安装路径,避免污染系统) cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/cmocka \ -DCMAKE_BUILD_TYPE=Release \ -DUNIT_TESTING=OFF # 关闭CMocka自身的单元测试 # 3. 编译+安装 make -j4 sudo make install
场景 2:嵌入式交叉编译(如 ARM Cortex-M)
# 1. 定义交叉编译工具链(替换为你的工具链路径) export CROSS_COMPILE=arm-none-eabi- export CC=${CROSS_COMPILE}gcc export AR=${CROSS_COMPILE}ar export STRIP=${CROSS_COMPILE}strip # 2. cmake配置(核心:指定交叉编译) cmake .. -DCMAKE_INSTALL_PREFIX=/your/project/cmocka-arm \ -DCMAKE_BUILD_TYPE=Release \ -DUNIT_TESTING=OFF \ -DCMAKE_SYSTEM_NAME=Generic \ # 无操作系统(裸机) -DCMAKE_C_FLAGS="-mthumb -mcpu=cortex-m4" # 适配你的MCU架构 # 3. 编译+安装到项目目录 make -j4 make install
关键说明:
  • 安装后会生成:
    • 头文件:include/cmocka.h
    • 库文件:lib/libcmocka.a(静态库,嵌入式优先用)

三、项目集成(3 步接入你的代码)

假设你的嵌入式项目结构如下:

your_project/ ├── src/ # 业务代码(如norflash_test.c) ├── test/ # 测试代码 ├── cmocka/ # 存放CMocka的头文件+库文件 └── CMakeLists.txt
步骤 1:复制 CMocka 文件到项目
# 复制头文件 cp /usr/local/cmocka/include/cmocka.h your_project/cmocka/ # 复制静态库(主机/嵌入式对应不同库) # 主机: cp /usr/local/cmocka/lib/libcmocka.a your_project/cmocka/ # 嵌入式: cp /your/project/cmocka-arm/lib/libcmocka.a your_project/cmocka/
步骤 2:编写 CMakeLists.txt(核心)
cmake_minimum_required(VERSION 3.10) project(embedded_test) # 1. 引入CMocka include_directories(${PROJECT_SOURCE_DIR}/cmocka) # 头文件路径 link_directories(${PROJECT_SOURCE_DIR}/cmocka) # 库文件路径 # 2. 要测试的业务代码(如norflash驱动) add_library(business_code STATIC src/norflash.c) # 3. 测试代码(如test_norflash.c) add_executable(norflash_test test/test_norflash.c) # 链接CMocka和业务代码 target_link_libraries(norflash_test business_code cmocka) # 嵌入式额外配置(根据你的MCU调整) if(ARM_EMBEDDED) set(CMAKE_C_FLAGS "-mthumb -mcpu=cortex-m4 -ffreestanding -nostdlib") # 链接脚本、启动文件等 target_link_libraries(norflash_test ${PROJECT_SOURCE_DIR}/src/link.ld) endif()
步骤 3:编写第一个测试用例(示例:NOR Flash 读写测试)

test/test_norflash.c中:

#include <cmocka.h> #include "norflash.h" // 你的NOR Flash驱动头文件 // 测试夹具:每个用例执行前初始化 static int setup_norflash_test(void **state) { // 模拟NOR Flash初始化(无需真实硬件) norflash_init(); return 0; } // 测试夹具:每个用例执行后清理 static int teardown_norflash_test(void **state) { // 模拟释放资源 norflash_deinit(); return 0; } // 测试用例1:验证NOR Flash读操作 static void test_norflash_read(void **state) { uint8_t buf[4] = {0}; // 调用被测函数:读取地址0x0000的4字节 int ret = norflash_read(0x0000, buf, 4); // 断言:返回值应为0(成功) assert_int_equal(ret, 0); // 断言:读取的数据符合预期(模拟场景可预设) assert_memory_equal(buf, (uint8_t[]){0x11, 0x22, 0x33, 0x44}, 4); } // 测试用例2:验证Mock函数调用(模拟写操作) static void test_norflash_write(void **state) { uint8_t data[] = {0xaa, 0xbb}; // 预设:期望norflash_erase被调用1次,入参为0x1000 expect_value(norflash_erase, addr, 0x1000); expect_call_count(norflash_erase, 1); // 执行被测函数 norflash_write(0x1000, data, 2); // 校验:norflash_erase确实被调用 check_expected_calls(); } // 注册测试用例 int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(test_norflash_read, setup_norflash_test, teardown_norflash_test), cmocka_unit_test(test_norflash_write), }; // 运行所有测试 return cmocka_run_group_tests(tests, NULL, NULL); }

四、运行验证

场景 1:Linux 主机运行
# 编译测试程序 cd your_project mkdir build && cd build cmake .. -DARM_EMBEDDED=OFF make -j4 # 运行测试 ./norflash_test

✅ 成功输出示例:

[==========] Running 2 test(s). [ RUN ] test_norflash_read [ OK ] test_norflash_read [ RUN ] test_norflash_write [ OK ] test_norflash_write [==========] 2 test(s) passed.
场景 2:嵌入式运行(裸机)
# 编译生成bin/hex文件 cmake .. -DARM_EMBEDDED=ON make -j4 # 下载到硬件(用你的烧录工具,如openocd/jlink) openocd -f interface/jlink.cfg -f target/stm32f4x.cfg -c "program norflash_test.hex verify reset exit"

✅ 验证方式:通过串口 / 调试器查看测试输出(需在代码中适配 printf 到串口)。

总结

  1. 核心步骤:下载 CMocka → 编译(主机 / 交叉编译)→ 项目集成(头文件 + 库 + CMake)→ 编写测试用例 → 运行验证;
  2. 嵌入式关键:交叉编译时指定CMAKE_SYSTEM_NAME=Generic和 MCU 架构参数,用静态库libcmocka.a
  3. 简化技巧:新手可先在 Linux 主机完成测试验证,再移植到嵌入式硬件。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 7:24:35

Seelen-UI桌面环境完全指南:打造你的专属Windows工作空间

Seelen-UI桌面环境完全指南&#xff1a;打造你的专属Windows工作空间 【免费下载链接】Seelen-UI The Fully Customizable Desktop Environment for Windows 10/11. 项目地址: https://gitcode.com/GitHub_Trending/se/Seelen-UI Seelen-UI作为Windows 10/11平台的完全可…

作者头像 李华
网站建设 2026/4/23 12:13:09

告别手绘时代:代码驱动神经网络可视化新体验

告别手绘时代&#xff1a;代码驱动神经网络可视化新体验 【免费下载链接】PlotNeuralNet Latex code for making neural networks diagrams 项目地址: https://gitcode.com/gh_mirrors/pl/PlotNeuralNet 还在为绘制神经网络结构图而熬夜加班吗&#xff1f;一张张手动调整…

作者头像 李华
网站建设 2026/4/23 10:11:02

Stacks Project 代数几何协作项目完全指南

Stacks Project 是一个协作的网络项目&#xff0c;致力于编写一本关于代数叠及其所需代数几何的教科书。该项目采用开源模式&#xff0c;汇集全球数学家的智慧&#xff0c;为学习者和研究者提供持续更新的宝贵资源。 【免费下载链接】stacks-project Repository for the Stacks…

作者头像 李华
网站建设 2026/4/22 14:12:24

Conda环境差异对比工具diff-environment使用指南

Conda环境差异对比工具diff-environment使用指南 在现代AI研发和数据科学项目中&#xff0c;我们经常遇到这样的问题&#xff1a;一段代码在同事的机器上运行完美&#xff0c;但在自己的环境中却频频报错。经过层层排查&#xff0c;最终发现罪魁祸首竟是某个依赖包版本相差了“…

作者头像 李华