• 测试驱动开发 001:VSCode + CMake + CppUTest 环境搭建


    本文是对《测试驱动的嵌入式 C 语言开发》第二章的实践。
    对资源受限的嵌入式项目如何进行测试驱动开发的所有疑问,都因为本书第二章最开始的一句话而消解,当我读到这句话时,脑袋里有闪电掠过。这句话是:我们在开发系统的本地来运行这些测试用例,而不是在目标平台上。

    搭建 VSCode

    这部分参考博文《基于Windows 的 VS Code C/C++ 编译环境搭建》

    安装 CMake

    安装 CMake ,在官网下载最新安装包。安装时选择对所有用户添加 CMake 到系统 PATH

    安装 VSCode 插件

    安装以下插件:

    • CMake:VSCode 的 CMake 语言支持插件
    • CMake Tools:对插件 CMake 的扩展支持

    下载 CppUTest

    CppUTest 是一个基于 C /C++ 的单元 xUnit 测试框架,用于单元测试和测试驱动开发。 它是用 C++ 编写的,但可以用于 C 和 C++ 项目,经常用于嵌入式系统,但它适用于任何 C/C++ 项目。
    可在官网下载源代码包,或者在Github拉取或下载源代码。

    使用 CppUTest

    1. 创建一个文件夹,这里命名为 TDDCppUTestExample
      文件夹内保存你的项目源文件、CppUTest 测试框架源文件、测试用例等,而现在,它只是一个空文件夹
    2. TDDCppUTestExample 文件夹下再创建一个文件夹,这里命名为 cpputest
      这个文件夹内存放 CppUTest 测试框架源文件:在从下载的 CppUTest 源码中将 srcinclude 两个文件夹拷贝到 cpputest 文件夹下。
    3. TDDCppUTestExample 文件夹下再创建一个文件夹,这里命名为 tests
      这个文件夹内存放所有测试用例。我们以测试 sprintf_s 函数为例。
      在 这个文件夹内创建 sprintf_s_test.cppall_tests.cpp 两个文件,其中sprintf_s_test.cpp 内容为:
    #include 
    #include "CppUTest/TestHarness.h"
    
    TEST_GROUP(sprintf)
    {
        void setup()
        {}
    
        void teardown()
        {}
    };
    
    TEST(sprintf, NoFrmatOperations)
    {
        char output[5];
    
        LONGS_EQUAL(3 , sprintf_s(output,4, "hey"));
        STRCMP_EQUAL("hey", output);
    }
    
    TEST(sprintf, FormatOperations)
    {
        char output[20];
        LONGS_EQUAL(12, sprintf_s(output, 20, "Hello %s\n", "World"));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    all_tests.cpp 内容为:

    #include "CppUTest/CommandLineTestRunner.h"
    #include "CppUTest/TestMemoryAllocator.h"
    #include "CppUTest/SimpleStringInternalCache.h"
    
    #define SHOW_MEMORY_REPORT 0
    
    int main(int ac, char **av)
    {
       int returnValue = 0;
       GlobalSimpleStringCache stringCache;
    
       {
           /* These checks are here to make sure assertions outside test runs don't crash */
           CHECK(true);
           LONGS_EQUAL(1, 1);
    
    #if SHOW_MEMORY_REPORT
           GlobalMemoryAccountant accountant;
           accountant.start();
    #endif
    
           returnValue = CommandLineTestRunner::RunAllTests(ac, av); /* cover alternate method */
    
    #if SHOW_MEMORY_REPORT
           accountant.stop();
           printf("%s", accountant.report().asCharString());
    #endif
       }
    
       return returnValue;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    1. TDDCppUTestExample 文件夹下创建名为 CMakeLists.txt 的文件,该文件给 CMake使用,文件内容为:
    # 最低CMake版本要求
    cmake_minimum_required(VERSION 3.5.1)
    
    # 获取源文件
    file(GLOB_RECURSE APP_SRC_DIR "tests/*.cpp")
    file(GLOB_RECURSE CPPUTEST_SRC_LIST "cpputest/src/CppUTest/*.cpp" "cpputest/src/Platforms/Gcc/*.cpp")
    
    # 项目名称
    project(TDD_test)
    
    #编译选项
    add_compile_options(-std=c++11)
    
    # 头文件路径
    include_directories("cpputest/include")
    include_directories("tests")
    
    #将所有源文件生成一个可执行文件
    add_executable(TDD_test  ${APP_SRC_DIR} ${CPPUTEST_SRC_LIST})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    1. 使用 VSCode 打开 TDDCppUTestExample 文件夹。单击下图所示红框中的三角形。
      在这里插入图片描述
      第一次执行会弹出选择编译套件的选项,这里选择 GCC
      在这里插入图片描述
      选择完毕,VSCode 会调用 CMake 根据 CMakeLists.txt 文件内容生成 Makefile 文件,然后调用指定编译器完成源代码编译,如果生成可执行文件,则执行可执行文件。 Makefile 文件以及编译生成文件会保存在 TDDCppUTestExample 文件夹下的 build 文件夹下,该文件夹由 VSCode 自动创建。
    [proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_C_COMPILER:FILEPATH=C:\msys64\mingw64\bin\gcc.exe -DCMAKE_CXX_COMPILER:FILEPATH=C:\msys64\mingw64\bin\g++.exe -Sc:/Users/jssh/Desktop/TDDCppUTestExample -Bc:/Users/jssh/Desktop/TDDCppUTestExample/build -G "Unix Makefiles"
    [cmake] Not searching for unused variables given on the command line.
    [cmake] -- The C compiler identification is GNU 12.2.0
    [cmake] -- The CXX compiler identification is GNU 12.2.0
    [cmake] -- Detecting C compiler ABI info
    [cmake] -- Detecting C compiler ABI info - done
    [cmake] -- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe - skipped
    [cmake] -- Detecting C compile features
    [cmake] -- Detecting C compile features - done
    [cmake] -- Detecting CXX compiler ABI info
    [cmake] -- Detecting CXX compiler ABI info - done
    [cmake] -- Check for working CXX compiler: C:/msys64/mingw64/bin/g++.exe - skipped
    [cmake] -- Detecting CXX compile features
    [cmake] -- Detecting CXX compile features - done
    [cmake] -- Configuring done
    [cmake] -- Generating done
    [cmake] -- Build files have been written to: C:/Users/jssh/Desktop/TDDCppUTestExample/build
    [main] Building folder: TDDCppUTestExample TDD_test
    [build] Starting build
    [proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --build c:/Users/jssh/Desktop/TDDCppUTestExample/build --config Debug --target TDD_test -j 14 --
    [build] [  4%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/tests/sprintf_s_test.cpp.obj[0m
    [build] [  8%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/tests/all_tests.cpp.obj[0m
    [build] [ 13%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/CommandLineArguments.cpp.obj[0m
    [build] [ 17%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/JUnitTestOutput.cpp.obj[0m
    [build] [ 21%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/CommandLineTestRunner.cpp.obj[0m
    [build] [ 26%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/SimpleMutex.cpp.obj[0m
    [build] [ 30%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/SimpleString.cpp.obj[0m
    [build] [ 34%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/MemoryLeakDetector.cpp.obj[0m
    [build] [ 39%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/SimpleStringInternalCache.cpp.obj[0m
    [build] [ 43%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/MemoryLeakWarningPlugin.cpp.obj[0m
    [build] [ 47%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/TeamCityTestOutput.cpp.obj[0m
    [build] [ 52%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/TestFailure.cpp.obj[0m
    [build] [ 56%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/TestFilter.cpp.obj[0m
    [build] [ 60%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/TestHarness_c.cpp.obj[0m
    [build] [ 65%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/TestOutput.cpp.obj[0m
    [build] [ 69%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/TestPlugin.cpp.obj[0m
    [build] [ 73%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/TestMemoryAllocator.cpp.obj[0m
    [build] [ 78%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/TestRegistry.cpp.obj[0m
    [build] [ 82%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/TestResult.cpp.obj[0m
    [build] [ 86%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/TestTestingFixture.cpp.obj[0m
    [build] [ 91%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/Platforms/Gcc/UtestPlatform.cpp.obj[0m
    [build] [ 95%] [32mBuilding CXX object CMakeFiles/TDD_test.dir/cpputest/src/CppUTest/Utest.cpp.obj[0m
    [build] [100%] [32m[1mLinking CXX executable TDD_test.exe[0m
    [build] [100%] Built target TDD_test
    [build] Build finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    Cmake 支持的快捷键,比较常用 Run Without Debugging

    在这里插入图片描述

    1. 终端 界面中,可以看到程序执行结果,也就是测试输出结果。
      在这里插入图片描述

    结束语

    如果你想使用测试驱动开发,又对本文举例内容疑惑,可能是因为你还没看过《测试驱动的嵌入式 C 语言开发》这本书。
    不要被书名欺骗到,这绝不仅仅只是教授你测试驱动方法的,它还教授 C 程序设计模式,如何改善设计、如何写出干净利落的代码,如何封装和模块化等等。

    另外,本书是这么多年来我看过的嵌入式翻译书籍中,翻译最准确最清晰的一本。一股清流,值得大书特书。
    同样为机械工业出版社,主讲设计模式的《C 嵌入式编程设计模式》毁在了翻译上。搞砸事情的人,有的是因为能力有问题,有的是因为职业素质有问题,而《C 嵌入式编程设计模式》的译者,显然二者兼有。





    读后有收获,资助博主养娃 - 千金难买知识,但可以买好多奶粉 (〃‘▽’〃)
    千金难买知识,但可以买好多奶粉


  • 相关阅读:
    【逗老师的无线电】MOTOTRBO CPS导入DMR ID通信录的骚操作
    Avito Cool Challenge 2018 F. Tricky Interactor(交互 构造)
    pinpoint新增自定义插件监控
    K8S Pod控制器:ReplicationController ReplicaSet Deployment三者的联系与区别
    c高级day1(9.6) 离线软件安装,文件相关指令,文件权限相关指令,
    网康科技 NS-ASG 应用安全网关 SQL注入漏洞复现(CVE-2024-2022)
    重新定义分析 - EventBridge 实时事件分析平台发布
    Java NIO开发需要注意的陷阱
    ElasticSearch (一)ElasticSearch 入门简介
    fashion_mnist.load_data()出现[winError 10054] 远程主机强迫关闭了一个现有的连接解决方法
  • 原文地址:https://blog.csdn.net/zhzht19861011/article/details/127547275