1. 单元测试环境搭建

任务说明

本案例目标是为嵌入式C语言项目搭建基于Unity的单元测试环境,配置编译器与模拟器,并编写、运行第一个测试用例。最终交付一个可独立复现的最小工程:被测模块、测试用例、构建脚本与运行方式。

工程结构


embedded_unity_demo/
├── src/
│   └── calculator.c
├── inc/
│   └── calculator.h
├── test/
│   └── test_calculator.c
├── unity/
│   ├── unity.c
│   ├── unity.h
│   └── unity_internals.h
└── Makefile

被测模块

实现一个简单的计算器模块,包含整数加法和除法函数。除法函数需处理除数为0的情况,返回0并设置错误标志。


// inc/calculator.h
#ifndef CALCULATOR_H
#define CALCULATOR_H

int add(int a, int b);
int divide(int a, int b, int *err);

#endif

// src/calculator.c
#include "calculator.h"

int add(int a, int b) {
    return a + b;
}

int divide(int a, int b, int *err) {
    if (b == 0) {
        *err = 1;
        return 0;
    }
    *err = 0;
    return a / b;
}

Unity框架获取

Unity官方源码位于GitHub仓库(https://github.com/ThrowTheSwitch/Unity.git)。将仓库中的src/unity.c、src/unity.h、src/unity_internals.h三个文件复制到工程的unity/目录。若无法联网,可手动创建空文件后从官方源补齐内容,本案例后续构建依赖这三个文件。

测试用例编写


// test/test_calculator.c
#include "unity.h"
#include "calculator.h"

void setUp(void) {}
void tearDown(void) {}

void test_add_positive_numbers(void) {
    TEST_ASSERT_EQUAL_INT(5, add(2, 3));
}

void test_add_negative_numbers(void) {
    TEST_ASSERT_EQUAL_INT(-2, add(-5, 3));
}

void test_divide_normal_case(void) {
    int err;
    TEST_ASSERT_EQUAL_INT(2, divide(10, 5, &err));
    TEST_ASSERT_EQUAL_INT(0, err);
}

void test_divide_by_zero(void) {
    int err;
    TEST_ASSERT_EQUAL_INT(0, divide(10, 0, &err));
    TEST_ASSERT_EQUAL_INT(1, err);
}

int main(void) {
    UNITY_BEGIN();
    RUN_TEST(test_add_positive_numbers);
    RUN_TEST(test_add_negative_numbers);
    RUN_TEST(test_divide_normal_case);
    RUN_TEST(test_divide_by_zero);
    return UNITY_END();
}

构建配置

使用GCC作为编译器,通过-fprofile-arcs -ftest-coverage选项生成覆盖率数据,便于后续分析。链接时使用--coverage。Makefile如下:


# Makefile
CC = gcc
CFLAGS = -Iinc -Iunity -Wall -Wextra -fprofile-arcs -ftest-coverage
LDFLAGS = --coverage
SRCS = src/calculator.c unity/unity.c test/test_calculator.c
TARGET = test_runner

all: $(TARGET)

$(TARGET): $(SRCS)
	$(CC) $(CFLAGS) $(SRCS) -o $(TARGET) $(LDFLAGS)

run: $(TARGET)
	./$(TARGET)

clean:
	rm -f $(TARGET) *.gcda *.gcno *.gcov

.PHONY: all run clean

运行与验证

在工程根目录执行以下命令:


make clean && make run

预期输出(确定性结果,由代码逻辑直接推出):


test_calculator.c:14:test_add_positive_numbers:PASS
test_calculator.c:18:test_add_negative_numbers:PASS
test_calculator.c:22:test_divide_normal_case:PASS
test_calculator.c:27:test_divide_by_zero:PASS

-----------------------
4 Tests 0 Failures 0 Ignored
OK

判定标准:若输出显示4个测试全部PASS且无Failures,则单元测试环境搭建成功,第一个测试用例通过。若需查看覆盖率,执行gcov test_calculator.c后查看生成的.gcov文件。

模拟器说明

本案例被测代码为纯C逻辑,不涉及硬件寄存器或外设访问,因此直接使用宿主机GCC编译运行即可完成验证。若后续被测模块包含硬件相关代码,可改用QEMU的arm-linux-gnueabi或qemu-arm配合交叉编译器运行,本案例不展开。

Unity单元测试环境搭建 — 构建与运行流程 src/calculator.c 被测模块实现 test/test_calculator.c 测试用例 unity/unity.c Unity框架源码 gcc 编译 -Iinc -Iunity --coverage test_runner 可执行测试程序 ./test_runner 执行测试 测试结果输出 4 Tests 0 Failures 0 Ignored OK gcov 覆盖率 calculator.c.gcov 源文件 编译/运行 产物 输出 覆盖率