1. C 单元测试框架1.1 什么是单元测试1.2 什么是单元测试框架1.3 常见单元测试框架1.4 引用2. MinUnit 单元测试框架简介2.1 简化版本组成2.2 简化版本范例2.3 完善版本示例2.3 引用3. CUnit 单元测试框架简介3.1 结构和常规用法3.1.1 常用的数据类型和函数在头文件说明3.1.2 CUnit 结构3.1.3 常规用法 — 典型流程3.2 安装和测试3.3 测试结果分析3.4 引用4. Unity 单元测试框架简介
1. C 单元测试框架
1.1 什么是单元测试
程序单元是应用的最小可测试部件。在过程编程中,一个单元就是单个程序、函数、过程等。而面向对象编程中,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法[1]。
单元测试是隔离程序单元, 单独进行检查校验,查看单元是否按设计意图工作。举个例子:测试算术加法函数,为了确保计算功能正常,传入不同参数值,比较返回值,这个就是单元测试。单元测试是软件测试重要步骤。
执行单元测试有如下优点:
- 可以及时发现问题,降低后期检测、识别和修正bug成本。
- 写一套全面的单元测试用例,会让用户自觉去考虑函数输入输出,错误情况,选择合理地组织架构。
- 可以有效控制系统熵增,完善单元测试给予集成测试信心。
- 开发框架更新迭代过程,程序的增删改经过单元测试验证,保证了开发框架质量。
- 帮助使用者了解接口功能和使用方法。
单元测试的局限在于难以发现集成问题或板载系统问题,难以覆盖所有执行路径和输入条件。复杂的测试用例设计增加了代码工作量(考虑到编码人员本身也是测试人员的情况)。单元测试需要版本控制记录修改内容,以便在失败时比对新老版本方便程序修改。为持续有效,单元测试需集成到团队工作流程中,定期审阅和及时调整,确保测试和程序更新同步。
1.2 什么是单元测试框架
单元测试框架提供了统一的编程模型,将测试定义为一些简单的类,这些类中的方法调用待测试的程序代码。开发人员不需要编写自己的测试控制工具,框架本身提供了用例组织与执行、丰富的断言方法、日志功能。单元测试框架还有如下优势:
- 指定单个检查的失败是否取消整个测试执行
- 具有可配置严重等级的检查器,还包括浮点数比较误差处理,检查到异常引发异常处理程序。
- 提供 suites 和 fixtures 等概念组织测试集。
- 提供丰富输出结果描述,可以导出XML 格式文件,结果可以集成到CI系统中。
总得来说帮助我们更好的完成自动化测试。
1.3 常见单元测试框架
ShiYanLou/常用C语言单元测试工具介绍.md at master · Ewenwan/ShiYanLou (github.com) 中介绍了C 语言单元测试常用工具。特别针对嵌入式系统,下面几种单元测试框架更为适用 [^1]。
- CUnit - A unit testing framework for C. Best suited for PC software
- EmbUnit -A unit testing framework for embedded systems. Best suited for systems with embedded Linux
- MinUnit - A minimalistic unit testing framework for C
1.4 引用
2. MinUnit 单元测试框架简介
对于资源有限的环境,比如 C 语言嵌入式系统,常用的单元测试框架会带来大量的资源消耗,并且嵌入式更多侧重功能测试,完善的框架实现并非必要。MinUnit 使用 C 语言编写,非常小型的单元测试框架。编译时未引用头文件中定义的宏函数,并不占会用内存。
Unit testing frameworks are quite popular in the object-oriented programming world. Frameworks like JUnit (for Java), SUnit (for Smalltalk), and CppUnit (for C++) provide a rich set of functionality. However, this rich set of functionality can be intimidating to someone who wants to do unit testing in a more constrained environment, such as an embedded system written in C. But the important thing about unit testing is the testing, not the framework. MinUnit is an extremely simple unit testing framework written in C. It uses no memory allocation, so it should work fine under almost any circumstance, including ROMable code.
2.1 简化版本组成
测试框架只有三行,有断言和
说明:
- 第一行断言,当测试条件不满足时,返回错误信息;
- 第二行运行测试,传入参数为函数指针,函数中无传入参数,当调用一次,全局变量测试次数
tests_run
自加 1。当返回的字符串不为空时,则返回messgage
;
- 第三行外部定义(extern)的运行次数,通知编译器在外部寻找 tests_run 变量。
注意:JTN002 — Jera Design LLC 中有提到,头文件中为什么使用
do{} while
结构?Question 10.4 (c-faq.com) 中有回答,宏中有多个声明时,为了防止替换后引入多个
“;”
。常规有两种解决方法:
第一种,使用
do{} while
结构,注意 while 后面没有 “;”
;第二种,使用一个括起来的表达式,里面包含一个或多个逗号操作符:
2.2 简化版本范例
关于简化版本的使用,可以参考 minunit_example.c
该部分可以从[这里]()下载测试
2.3 完善版本示例
minunit
siu • Updated Nov 21, 2024
It provides a way to define and configure test suites and a few handy assertion types. It reports the summary of the number of tests run, number of assertions and time elapsed.
基于简化版本,该项目添加了常用功能,比如测试组、常见类型断言、报告测试数目、断言数目和耗时。
输出结果:
2.3 引用
- uCUnit: Main Page Unit Test Framework for Microcontrollers
3. CUnit 单元测试框架简介
CUnit 是一个编写、管理和运行 C 语言单元测试架构,会通过静态库链接在用户编写的测试代码中。CUnit 具有测试框架简洁、支持丰富数据类型断言、并提供多种运行测试和报告测试结果接口。接口包括自动化接口(Automated interface )和交互式接口(Interactive interface),其中交互式有控制窗和图形窗两种方式)。[^2]
- 自动化接口 - Automated interface

- 交互式接口-Interactive interface()

3.1 结构和常规用法
3.1.1 常用的数据类型和函数在头文件说明
Header File | Description |
#include <CUnit/CUnit.h> | ASSERT macros for use in test cases, and includes other framework headers. |
#include <CUnit/CUError.h> | Error handing functions and data types. Included automatically by CUnit.h. |
#include <CUnit/TestDB.h> | Data type definitions and manipulation functions for the test registry, suites, and tests. Included automatically by CUnit.h. |
#include <CUnit/TestRun.h> | Data type definitions and functions for running tests and retrieving results. Included automatically by CUnit.h. |
#include <CUnit/Automated.h> | Automated interface with xml output. |
#include <CUnit/Basic.h> | Basic interface with non-interactive output to stdout. |
#include <CUnit/Console.h> | Interactive console interface. |
#include <CUnit/CUCurses.h> | Interactive console interface (*nix). |
#include <CUnit/Win.h> | Windows interface (not yet implemented). |
3.1.2 CUnit 结构
CUnit 的框架组织和常见单元测试框架一致,主要有 test registry、test suites 和 test cases 组成,框架组织如下:
Test Cases 会被打包进 Test Suites,Test Suites 注册进 Test Registry 中。Test Suites 运行前有 setup 函数,准备同样的上下文环境 ,运行后调用 teardown 函数恢复初始状态。Test Registry 中测试工作放在单个函数中执行。
3.1.3 常规用法 — 典型流程
- 写测试函数 Write functions for tests (and suite init/cleanup if necessary).
- 初始化测试注册表 Initialize the test registry - CU_initialize_registry()
- 将测试组添加到测试注册表中 Add suites to the test registry - CU_add_suite()
- 将测试函数添加到测试组中 Add tests to the suites - CU_add_test()
- 用合适的接口运行测试 Run tests using an appropriate interface, e.g. CU_console_run_tests
- 清除测试注册表Cleanup the test registry - CU_cleanup_registry
该部分主要翻译自 CUnit 用户手册[^3]。
3.2 安装和测试
Linux 安装请参考 linux下的Cunit的编译与安装 (测试可行)和 
CUnit
Github
CUnit
Owner
jacklicnUpdated
Nov 15, 2024Winows 安装请参考 Windows 和 linux 下CUnit编译安装教程(未测试,但是目前找到最全面的)
STM32 嵌入式平台移植请参考 Cunit在嵌入式平台上的移植(STM32)
在不同平台上输出大同小异,这里编译测试在 Ubuntu20.04 环境下,参考上文 Linux 系统下安装,CUnit 安装在 /opt/Cunit。
测试文件为下载解压好的 /home/username/Desktop/CUnit-2.1-3/Examples/BasicTest/BasicTest.c 。
编译 BasicTest
说明:
- /opt/Cunit/lib/libcunit.a , 链接静态库
- -I../ , 引入 "ExampleTests.h" 头文件路径
- -I/opt/Cunit/include/CUnit , 引入 "Basic.h" 头文件路径
3.3 测试结果分析
输出结果(每组前使用 “// ” 注释,实际输出不会存在)
3.4 引用
- CUnit - Table of Contents (sourceforge.net) Cunit User Guide
4. Unity 单元测试框架简介
Unity 也是专为 C 语言,特别是嵌入式场景开发的单元测试框架,本身由一个C文件和一系列头文件组成,移植方便。比起 MinUnit,Unity 断言更为丰富,额外支持数组、位、内存等断言功能。更多内容可以直接访问下面仓库地址。
Unity
ThrowTheSwitch • Updated Nov 28, 2024
Welcome to the Unity Test Project, one of the main projects of ThrowTheSwitch.org. Unity Test is a unit testing framework built for C, with a focus on working with embedded toolchains.
This project is made to test code targetting microcontrollers big and small. The core project is a single C file and a pair of headers, allowing it to be added to your existing build setup without too much headache. You may use any compiler you wish, and may use most existing build systems including Make, CMake, etc. If you'd like to leave the hard work to us, you might be interested in Ceedling, a build tool also by ThrowTheSwitch.org.
- 添加 C 模块单独测试文件
- 测试文件包含 unity.h
- 测试文件包括 C 模块头文件
- 添加
setUp()
测试前准备测试环境 - 没有参数也没有返回值
- 添加
tearDown()
测试后清除相关设置 - 没有参数也没有返回值
- 添加测试函数(以test_开头,便于其他开发人员确定函数功能)
- 没有参数也没有返回值
- 添加main函数(可使用generate_test_runner.rb脚本帮助生成)
UNITY_BEGIN()
RUN_TEST
UNITY_END()