C代码单元测试框架

如何在Windows本地集成unity和CMocka单元测试框架?

 

一、Cmocka源码下载编译

   官方网站 https://cmocka.org/ 下载源码。

     CMocka 使用 CMake 来管理构建过程,它能自动生成适用于 MinGW 的构建文件(MinGW Makefiles)。如果你想要在 Windows 上使用MinGW 编译 CMocka则需要用到CMake工具。

     CMake 是一个构建系统生成工具,它的作用是帮助你生成适用于不同平台的构建文件,如: Makefile。

     MinGW 是一个编译工具链,提供了 GCC 编译器等工具,用于在 Windows 上编译 C、C++ 等程序。

二、下载和安装 MinGW

  1、下载:访问 MinGW官方网站。 Download File List - MinGW - Minimalist GNU for Windows - OSDN

    

  2、安装配置

    安装时,确保选择以下组件(选择后点击apply应用继续安装):  

    (1)、mingw32-base:基础开发工具。

    (2)、mingw32-gcc-g++:C 和 C++ 编译器。

    (3)、(可选)mingw32-msys-base:如果你希望使用类似 Unix 的环境,可以选择安装。

  3、设置环境变量

 

    安装完成后,你需要将 MinGW 的 bin 目录添加到系统的环境变量 中,这样你就可以在任何位置使用 MinGW 编译工具。

 

    (1)、右键点击“此电脑”或“计算机”,选择“属性”。

    (2)、点击“高级系统设置”,然后选择“环境变量”。

    (3)、在 系统变量 中找到 Path,点击“编辑”。

    (4)、在编辑窗口中,点击“新建”并添加 MinGW 安装路径下的 bin 目录,例如:C:\MinGW\bin(根据你实际的安装路径)。

    (5)、保存并退出。

   4、测试安装成功

    (1)、打开 命令提示符(cmd)。

    (2)、输入  gcc --version  命令来检查 GCC 是否安装成功

三、下载和安装 CMake

  1、下载 CMake:访问 CMake 的 下载页面,并下载适合 Windows 的安装包。  Download CMake

    

安装时可以选择 Add CMake to system PATH(将 CMake 添加到系统 PATH),这样你可以在命令行中直接使用 cmake 命令。

   2、验证安装:安装完成后,你可以在命令行中运行以下命令,确认 CMake 是否安装成功:
    (1)、cmake --version (如果找不到可以尝试重新开启cmd命令提示框)

四、使用 CMake 构建 CMocka

  1、进入你下载的 CMocka 源代码目录

    cd path/to/cmocka

  2、创建一个新的构建目录:

    mkdir build

    cd build

  3、使用 CMake 配置构建过程:

    cmake ..

    (1)、如果你希望指定 MinGW 编译器,可以使用 -G 选项来告诉 CMake 使用 MinGW 构建。例如:

         cmake -G "MinGW Makefiles" ..

           这将告诉CMake使用MinGW的make工具来生成Makefile。

  4、开始构建 CMocka:

    make

   5、开始安装 CMocka:

    make install

   6、常见错误提示

    提示:CMake Error at cmake_install.cmake:41 (file): file cannot create directory: C:/Program Files (x86)/cmocka/lib/pkgconfig. Maybe need administrative privileges.

      此时需要已管理员方式运行你的终端,windows下可以在搜索框中搜索cmd,在弹出的运用程序中选择以管理员方式运行。

   7、如果构建成功,CMocka 的库文件将被生成。

    库文件生成目录:文件将被安装到 C:/Program Files (x86)/cmocka/ 目录中。

五、验证CMocka是否安装成功

  构建和安装完成后,你可以通过以下步骤验证 CMocka 是否安装成功。

  1、在终端中检查 CMocka 库是否被安装到正确的位置。

  2、编译运行测试程序

    (1)、创建一个 test_example.c 文件:

#include <cmocka.h>

static void test_example(void **state) {
    (void) state;  // unused variable
    assert_int_equal(1, 1);  // Example test: asserts that 1 == 1
}

int main(void) {
    const struct CMUnitTest tests[] = {
        cmocka_unit_test(test_example),
    };
    return cmocka_run_group_tests(tests, NULL, NULL);
} 

    (2)、用 MinGW 编译并运行测试(windows搜索框中搜索cmd,以管理员方式运行):

        gcc -o test_example test_example.c -lcmocka

        也能写makefile自动编译运行

# Makefile for testing with CMocka

# 编译器和编译选项
CC = gcc
# CMocka 的头文件路径
CFLAGS = -Wall -std=c99 -I"C:/Program Files (x86)/cmocka/include" 
# CMocka 的库文件路径
LDFLAGS = -L"C:/Program Files (x86)/cmocka/lib" -lcmocka  

# 目标可执行文件
TARGET = test_program.exe

# 源文件
#SRCS = test_program.c

# 自动查找当前目录下的所有 .c 文件  不仅是test_program.c文件,还包含了库里的其它C文件
SRCS = $(wildcard *.c)

# 目标文件
OBJS = $(SRCS:.c=.o)

# 默认目标
all: $(TARGET)

# 编译可执行文件
$(TARGET): $(OBJS)
    $(CC) $(OBJS) $(LDFLAGS) -o $(TARGET)

# 编译源文件
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

# 清理目标
# Windows 删除命令
clean:
    rm -f $(OBJS) $(TARGET)  

# 运行程序
run: $(TARGET)
# 运行生成的 .exe 文件
    ./$(TARGET)  

         

  3、常见错误提示

    (1)、提示找不到头文件时使用绝对路劲:gcc -I"C:/Program Files (x86)/cmocka/include" -L"C:/Program Files (x86)/cmocka/lib" -o test_example test_example.c -lcmocka

    (2)、使用绝对路劲如果提示cmocka.h下的各种错误,证明测试程序已经能找到cmocka.h了,此时我们进入C:/Program Files (x86)/cmocka/include下找到cmocka.h,打开源代码发现提示使用时必须包含提供的头文件。在源代码头部添加后再编译就没有报错了。

          

    (3)、由于找不到cmocka.dll,无法继续执行代码。重新安装程序可能会解决此问题。

        但我们查询到这个文件在C:\Program Files (x86)\cmocka\bin 目录下,将此路径添加到系统环境变量path下即可。

  4、运行测试程序:

    编译成功会在同路劲下生成 test_example.exe文件,在cmd下运行命令:test_example.exe ,也可以双击运行。

   windows运行:test_example.exe    linux:./test_example
  
   如果使用makefile文件编译,我们可以在cmd命令框输入make编译,make run运行编译后的.exe程序,make clean来清空编译生成的.o和.exe文件。   
  
   成功运行如下:

        

六、下载 Unity 测试框架源代码

  只需unity.c  unity.h  unity_internals.h即可

   下载:访问 Unity GitHub 页面

      (1)、点击 "Code" 按钮,然后选择 "Download ZIP" 进行下载。

      (2)、解压缩下载的文件到你选择的目录。

                  

 七、在CMocka的工程上使用unity——unity集成CMocka

  1、首先将下载的unity源文件放到我们的工程路劲

    

  2、在test_example.c文件下包含unity.h头文件

    make

    提示错误:找不到unity.h头文件,我们修改makefile,增加unity.h放置的绝对路劲,如下:

    

# Makefile for testing with CMocka

# 编译器和编译选项
CC = gcc
# CMocka 的头文件路径
CFLAGS = -Wall -std=c99 -I"C:/Program Files (x86)/cmocka/include" -I D:/CMocka/test/unity_cmocka_test 
# CMocka 的库文件路径
LDFLAGS = -L"C:/Program Files (x86)/cmocka/lib" -lcmocka  

# 目标可执行文件
TARGET = test_program.exe

# 源文件
#SRCS = test_program.c

# 自动查找当前目录下的所有 .c 文件
SRCS = $(wildcard *.c)

# 目标文件
OBJS = $(SRCS:.c=.o)

# 默认目标
all: $(TARGET)

# 编译可执行文件
$(TARGET): $(OBJS)
    $(CC) $(OBJS) $(LDFLAGS) -o $(TARGET)

# 编译源文件
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

# 清理目标
# Windows 删除命令
clean:
    rm -f $(OBJS) $(TARGET)  

# 运行程序
run: $(TARGET)
# 运行生成的 .exe 文件
    ./$(TARGET)  

  3、执行编译指令:make

        报错如下:证明已经能正确找到unity.h头文件

              unity.o:unity.c:(.text+0x26e4):    undefined reference to `setUp'

              unity.o:unity.c:(.text+0x26fe):     undefined reference to `tearDown'

    这两个接口需要我们自己实现在主函数里,这是两个回调函数,执行测试用例前后会自动调用。执行前就可以用CMocka模拟参数传入测试用例了。

   unity单元测试示例:

 1 #include <stdarg.h>
 2 #include <stddef.h>
 3 #include <stdint.h>
 4 #include <setjmp.h>
 5 #include <stdint.h>
 6 
 7 #include <cmocka.h>
 8 
 9 #include <unity.h>
10 
11 
12 // 被测试的函数(示例)
13 int add(int a, int b) {
14     return a + b;
15 }
16 
17 // 单元测试函数1
18 void test_add_two_positive_numbers(void) {
19     TEST_ASSERT_EQUAL_INT(5, add(2, 3));  // 断言 2 + 3 等于 5    5预期结果  2 和 3 是传入的结果,如果传入的参数运行结果跟预期结果不一致,就会产生断言
20 }
21 // 单元测试函数2
22 void test_add_negative_and_positive(void) {
23     TEST_ASSERT_EQUAL_INT(10, add(3, 6));  //  断言 3 + 6 = 9  这个运行就会产生断言   运行结果与预期值不符
24 }
25 
26 // setUp 函数在每个测试用例之前执行(回调函数)    每个测试用例执行前都会执行这个函数
27 void setUp(void) {
28     // 初始化工作,例如分配内存、初始化变量等
29 }
30 
31 // tearDown 函数在每个测试用例之后执行(回调函数)  测试用例产生断言就会执行这个函数
32 void tearDown(void) {
33     // 清理工作,例如释放内存、重置状态等
34 }
35 
36 static void test_example(void **state) {
37     (void) state;  // unused variable
38     assert_int_equal(1, 1);  // Example test: asserts that 1 == 1
39 }
40 
41 
42 int main(void) {
43     /*unity*/
44     UNITY_BEGIN();//初始化unity测试框架
45     RUN_TEST(test_add_two_positive_numbers);//运行unity单元测试
46     RUN_TEST(test_add_negative_and_positive);//运行unity单元测试
47     UNITY_END();//结束测试
48     
49     /*CMocka*/
50     const struct CMUnitTest tests[] = {
51         cmocka_unit_test(test_example),
52     };
53     
54     return cmocka_run_group_tests(tests, NULL, NULL); 
55 }

  4、CMocka集成到unity下成功运行如下

    

  5、unity扩展用法  

    (1)、自定义断言  

//自定义断言   断言返回的数据在参数1 2 范围内
#define TEST_ASSERT_FLOAT_WITHIN_MY(expected1, expected2, actual) TEST_ASSERT_TRUE((expected1 < actual) && (actual < expected2)?1:0)   
void test_float_out_range(void) {
    
    TEST_ASSERT_FLOAT_WITHIN_MY(0.0, 100.0, float_add(3.14,99.14));    
}

//自定义断言  断言一个浮动值在一个给定的误差范围内 
#define TEST_ASSERT_FLOAT_OUT_RANGE(expected, tolerance, actual) TEST_ASSERT_TRUE(fabs((actual) - (expected)) < (tolerance))
void test_float_within_tolerance(void) {
    float tolerance = 30.0;
    TEST_ASSERT_FLOAT_OUT_RANGE(80.0, tolerance, 100.0);    
}

    (2)、测试套件

        可以创建多个测试套件。通过这种方式,你可以组织并运行一组测试,而不必每次都单独调用每个测试函数。

// 将多个测试函数添加到一个测试套件中
void test_suite(void) {//同组测试套件可以是相关功能的几个测试函数,参数可以关联起来
    RUN_TEST(test_add_two_positive_numbers);
    RUN_TEST(test_add_negative_and_positive);
}

int main(void) {
    UNITY_BEGIN();  // 开始测试
    test_suite();  // 运行测试套件
    return UNITY_END();  // 结束测试
}

    (3)、性能测试

        通过记录函数执行的时间,来测量代码的性能 

#include "unity.h"
#include "timer.h"  // 假设你有一个计时器库

void test_performance_of_function(void) {
    uint32_t start_time = timer_get_current_time();
    
    // 调用需要测试性能的函数
    some_function_to_test();
    
    uint32_t end_time = timer_get_current_time();
    uint32_t elapsed_time = end_time - start_time;
    
    // 假设你有一个性能限制,比如函数执行时间不能超过 100ms
    TEST_ASSERT_TRUE(elapsed_time < 100);
}

    (4)、跳过某些测试

        某些情况下可能不希望运行某些测试,比如依赖于外部硬件的测试。Unity 提供了一个 TEST_IGNORE() 宏来跳过某个测试。

        void test_that_is_skipped(void)

        {

          TEST_IGNORE(); // 跳过此测试 // 这部分代码永远不会执行

        }

    (5)、测试结果输出控制

        可以通过 UNITY_OUTPUT_CHAR()UNITY_OUTPUT_INT() 等宏自定义输出方式。你可以把测试结果输出到不同的地方,例如文件、串口、或通过调试端口。

八、强制为现有目录启用 8.3 文件名

  有时我们在输入C:\Program Files (x86) 这种文件名时,因为有空格,有些编译器识别不了,需要其它操作,windows下这类文件目录对应一个短文件名,如何使用呢?

  你可以使用 fsutil 工具来强制更新现有目录的 8.3 文件名。按以下步骤操作:

  1、打开 命令提示符(以管理员身份运行)。

  2、输入以下命令以强制重新生成 C:\Program Files (x86) 目录下的 8.3 文件名:

    fsutil 8dot3name set C:\Program Files (x86) 0

  使用 dir /x命令

    完成上述步骤后,运行 dir /x 命令查看目录内容时,应该可以看到 8.3 文件名了。例如:

      

    虽然 Progra~2 是 Program Files (x86) 的短路径表示法,但并不是所有的工具或者环境都能够正确解析这种表示法。如果还是发现引用不到路劲中的头文件,就使用“path/./..”方法。

 

 

 

  

 

 

posted @ 2024-11-08 11:13  耿通宇  阅读(29)  评论(0编辑  收藏  举报