Unity 单元测试框架用法 - 教程
目录
一、常用断言宏(判断测试结果的核心工具)
Unity 提供了丰富的断言宏,覆盖不同数据类型和判断场景,核心作用是验证 “实际结果” 是否符合 “预期结果”。除了TEST_ASSERT_EQUAL_INT,常用的还有这些:
1.相等性断言(判断两个值是否相等)
TEST_ASSERT_EQUAL_INT8(expected, actual):判断 8 位整数相等(如int8_t)TEST_ASSERT_EQUAL_UINT(expected, actual):判断无符号整数相等TEST_ASSERT_EQUAL_HEX(expected, actual):以十六进制判断整数相等(适合底层数据验证)TEST_ASSERT_EQUAL_FLOAT(expected, actual, tolerance):判断浮点数相等(tolerance是允许的误差范围,如0.001)TEST_ASSERT_EQUAL_STRING(expected, actual):判断字符串内容相等(区分大小写)TEST_ASSERT_EQUAL_MEMORY(expected, actual, length):判断指定长度的内存块完全相等(适合结构体、数组等)示例:
// 验证浮点数相等(允许0.01的误差)
TEST_ASSERT_EQUAL_FLOAT(3.14, calculate_pi(), 0.01);
// 验证字符串相等
TEST_ASSERT_EQUAL_STRING("hello", get_greeting());
2.不等性断言(判断两个值是否不相等)
TEST_ASSERT_NOT_EQUAL_INT(expected, actual):整数不相等TEST_ASSERT_NOT_EQUAL_STRING(expected, actual):字符串不相等
// 验证除数不为0时,返回值不等于-1(结合你的divide_func)
TEST_ASSERT_NOT_EQUAL_INT(-1, divide_func(4, 2));
3.布尔 / 条件断言(判断真假或条件)
TEST_ASSERT_TRUE(condition):验证条件为真(非 0)TEST_ASSERT_FALSE(condition):验证条件为假(0)TEST_ASSERT(condition):等价于TEST_ASSERT_TRUE,更简洁
// 验证"除数为0时返回-1"这个条件为真
TEST_ASSERT_TRUE(divide_func(5, 0) == -1);
4.空指针断言(判断指针是否为空)
TEST_ASSERT_NULL(pointer):验证指针为NULLTEST_ASSERT_NOT_NULL(pointer):验证指针不为NULL
TEST_ASSERT_NOT_NULL(create_object()); // 验证创建的对象指针非空
5.范围断言(判断值是否在指定范围内)
TEST_ASSERT_GREATER_THAN(threshold, actual):实际值大于阈值TEST_ASSERT_LESS_THAN(threshold, actual):实际值小于阈值
// 验证除法结果为正数(假设除数和被除数同号)
TEST_ASSERT_GREATER_THAN(0, divide_func(6, 2));
二、测试生命周期管理(setUp 和 tearDown)
代码中已经定义了setUp和tearDown函数,它们是 Unity 中管理测试前置 / 后置操作的核心:
setUp(void):每个测试函数运行前自动调用,用于初始化资源(如创建临时变量、打开文件、初始化结构体等)。tearDown(void):每个测试函数运行后自动调用,用于清理资源(如释放内存、关闭文件、重置状态等)。
作用:确保每个测试函数独立运行,不受其他测试的影响(测试独立性原则)。
示例:
// 定义一个全局变量,用于测试
int test_result;
// 每个测试前初始化
void setUp(void) {
test_result = 0; // 重置结果变量
}
// 每个测试后清理
void tearDown(void) {
// 假设需要释放动态内存
// free(some_ptr);
}
// 测试1:验证加法
void test_add(void) {
test_result = 2 + 3;
TEST_ASSERT_EQUAL_INT(5, test_result);
}
// 测试2:验证减法
void test_subtract(void) {
test_result = 5 - 1; // 不受test_add中赋值的影响(因为setUp会重置)
TEST_ASSERT_EQUAL_INT(4, test_result);
}
三、测试运行控制
1.忽略某个测试(暂时不执行)
如果某个测试暂时不需要运行(如未完成的功能),可以用TEST_IGNORE()在测试函数中标记,Unity 会跳过该测试并记录为 “忽略”。
void test_unfinished_feature(void) {
TEST_IGNORE(); // 跳过这个测试
TEST_ASSERT_EQUAL_INT(10, some_unfinished_func());
}
2.批量运行多个测试
通过RUN_TEST()宏可以在UNITY_BEGIN()和UNITY_END()之间批量执行多个测试函数,顺序执行。
void test_unity(void) {
UNITY_BEGIN();
RUN_TEST(test_func); // 运行测试1
RUN_TEST(test_zero_catch); // 运行测试2
RUN_TEST(test_add); // 运行测试3
UNITY_END();
}
3.自定义测试输出信息
断言失败时,默认会输出预期值、实际值和位置。如果需要添加自定义说明,可以用TEST_ASSERT_EQUAL_INT_MESSAGE(其他断言宏同理,加_MESSAGE后缀)。
// 失败时会额外输出"除数为0的错误码验证失败"
TEST_ASSERT_EQUAL_INT_MESSAGE(-1, divide_func(3, 0), "除数为0的错误码验证失败");
四、测试报告与配置
Unity 会自动统计测试总数、失败数、忽略数,并在UNITY_END()时输出最终报告(如OK (3 tests)或FAIL (1 of 3 tests))。
你还可以通过宏定义配置 Unity 的行为,例如:
UNITY_OUTPUT_COLOR:启用彩色输出(区分成功 / 失败)。
// 启用彩色输出(必须在包含unity.h之前)
#define UNITY_OUTPUT_COLOR
#include "unity.h"
UNITY_SUPPORT_64:支持 64 位整数断言(如TEST_ASSERT_EQUAL_INT64)。自定义输出函数:将测试结果输出到串口、文件等(适合嵌入式环境)。
示例(配置输出到串口):
// 自定义输出函数(假设串口打印函数为uart_puts)
void unity_output_char(char c) {
uart_puts(&c, 1); // 输出到串口
}
// 在UNITY_BEGIN()前注册自定义输出
UNITY_EXTERN void UnityOutputChar(char c);
#define UnityOutputChar unity_output_char
五、参数化测试(灵活验证多组输入)
Unity 本身不直接支持参数化测试,但可以通过宏或循环手动实现:对同一函数用多组输入值测试,避免编写重复的测试函数。
// 多组测试数据:{输入a, 输入b, 预期结果}
typedef struct {
int a;
int b;
int expected;
} DivideTestData;
DivideTestData test_cases[] = {
{6, 3, 2}, // 正常除法
{5, 2, 2}, // 整数除法截断
{4, -1, -4}, // 负数除法
{0, 5, 0} // 被除数为0
};
// 批量执行多组测试
void test_divide_parametric(void) {
int num_tests = sizeof(test_cases) / sizeof(test_cases[0]);
for (int i = 0; i < num_tests; i++) {
DivideTestData* case_data = &test_cases[i];
int result = divide_func(case_data->a, case_data->b);
// 输出当前测试组的信息,方便定位失败
TEST_ASSERT_EQUAL_INT_MESSAGE(
case_data->expected,
result,
"测试组 %d 失败", i
);
}
}
单元测试它后面就是个测试集,随时拿出来用,你比如你切换完平台后,或者iic驱动程序重新改了以后,你跑一下单元测试快速验证,比如在环境变化时(切换芯片,切换底层库和驱动),你能迅速验证你的驱动是正常工作的。

浙公网安备 33010602011771号