Unity 单元测试框架用法
目录
一、常用断言宏(判断测试结果的核心工具)
1.相等性断言(判断两个值是否相等)
2.不等性断言(判断两个值是否不相等)
二、测试生命周期管理(setUp 和 tearDown)
三、测试运行控制
1.忽略某个测试(暂时不执行)
2.批量运行多个测试
3.自定义测试输出信息
四、测试报告与配置
五、参数化测试(灵活验证多组输入)
一、常用断言宏(判断测试结果的核心工具)
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)
:验证指针为NULL
-
TEST_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); // 运行测试1RUN_TEST(test_zero_catch); // 运行测试2RUN_TEST(test_add); // 运行测试3UNITY_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驱动程序重新改了以后,你跑一下单元测试快速验证,比如在环境变化时(切换芯片,切换底层库和驱动),你能迅速验证你的驱动是正常工作的。