使用 GoogleTest 对 ESP-IDF 组件进行单元测试(基于主机)

发布: (2026年2月22日 GMT+8 14:05)
5 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的具体文本内容(文章正文、代码块除外),我将按照要求保持原有的 Markdown 格式和技术术语,仅翻译文本部分为简体中文。谢谢!

Introduction

我想要一种方法,在不每次都烧录板子的情况下测试 ESP‑IDF 组件逻辑。
ESP‑IDF 可以为 Linux 目标构建,从而让测试直接在主机上运行。
本指南展示如何使用 GoogleTest 作为测试框架进行设置。示例仓库是 aluigiotomazelli/gtest‑esp‑idf(章节 01_basic_test)。

前置条件

  • ESP‑IDF 5.x 已安装并已 source
  • Linux 机器或 WSL2
  • ESP‑IDF Linux 目标所需的系统软件包
sudo apt install libbsd0 libbsd-dev

如果使用官方 ESP‑IDF Docker 容器(idf-env:latest),这些软件包已经预装。

注意: Ruby 仅在基于 CMock 的 IDF mock 中需要,相关内容将在后面的章节中介绍。

仓库布局

01_basic_test/
├── CMakeLists.txt
├── include/
│   ├── i_sum.hpp     # Interface (abstract base class)
│   └── sum.hpp       # Concrete class header
├── src/
│   └── sum.cpp       # Production code
├── host_test/
│   ├── gtest/        # GTest wrapper component (CMake only)
│   └── test_sum/    # Test project for the Sum class
└── test_apps/        # Hardware verification (not used for host tests)
  • src/include/ 包含生产代码。
  • host_test/ 包含所有主机端测试代码;这两个目录从不混用。

i_sum.hpp

Sum 定义了一个抽象基类。虽然在这个简单示例中并非严格必需,但它展示了一种在以后使用 GMock 进行模拟时会很有用的模式。

将 GoogleTest 添加为组件

GoogleTest 并不是 ESP‑IDF 的一部分,因此我们通过位于 host_test/gtest/ 的包装组件来引入它。该包装组件仅包含一个 CMakeLists.txt 文件:

# host_test/gtest/CMakeLists.txt
if(IDF_TARGET STREQUAL "linux")
    include(FetchContent)

    FetchContent_Declare(
        googletest
        GIT_REPOSITORY https://github.com/google/googletest.git
        GIT_TAG        v1.14.0
    )

    # FetchContent 必须在真实的构建阶段运行,而不是依赖扫描阶段
    if(NOT CMAKE_BUILD_EARLY_EXPANSION)
        FetchContent_MakeAvailable(googletest)
    endif()

    # 注册为 INTERFACE 库,以便其他组件可以链接 GTest/GMock
    add_library(gtest INTERFACE)
    target_link_libraries(gtest INTERFACE gtest gmock)
    target_include_directories(gtest INTERFACE
        ${googletest_SOURCE_DIR}/include
    )
endif()

关键点

  • 仅限 Linux 的守护 – 仅当构建目标为 linux 时才会处理该组件。
  • FetchContent – 在构建时下载 GTest;只需更改 GIT_TAG 即可更新版本。
  • 构建阶段守护 – 防止在早期依赖扫描阶段尝试下载。
  • INTERFACE 库 – 包装本身不编译任何代码;它仅向 REQUIRES 它的项目公开 GTest/GMock。

测试项目配置

测试项目位于 host_test/test_sum/。重要的 CMake 设置如下:

# host_test/test_sum/CMakeLists.txt
cmake_minimum_required(VERSION 3.16)

set(EXTRA_COMPONENT_DIRS
    "${CMAKE_CURRENT_LIST_DIR}/../../.."   # 仓库根目录(包含待测试的组件)
    "${CMAKE_CURRENT_LIST_DIR}/../gtest"   # GTest 包装器
)

idf_component_register(
    SRCS "test_sum.cpp"
    INCLUDE_DIRS "."
    REQUIRES sum gtest
    WHOLE_ARCHIVE   # 确保静态构造函数(GoogleTest 注册)不会被丢弃
)
  • EXTRA_COMPONENT_DIRS 指向待测试的组件 (sum) 和 GTest 包装器,它们位于测试项目文件夹之外。
  • REQUIRES 只列出所需的组件,以保持构建速度。
  • WHOLE_ARCHIVE 强制包含所有目标文件,以便 GoogleTest 能够发现测试。

示例测试代码

// host_test/test_sum/test_sum.cpp
#include 
#include "sum.hpp"

TEST(TestSum, GTestSmokeTest) {
    EXPECT_TRUE(true);   // verifies that GoogleTest itself runs
}

TEST(TestSum, Add) {
    Sum s;
    EXPECT_EQ(s.add(2, 3), 5);
    EXPECT_EQ(s.add(-1, -4), -5);
    EXPECT_EQ(s.add(0, 0), 0);
}

TEST(TestSum, AddConstrained_InRange) {
    Sum s;
    EXPECT_EQ(s.add_constrained(3, 4), 7);   // 7 ≤ 10
}

TEST(TestSum, AddConstrained_AtLimit) {
    Sum s;
    EXPECT_EQ(s.add_constrained(5, 5), 10);  // exactly the limit
}

TEST(TestSum, AddConstrained_OutOfRange) {
    Sum s;
    EXPECT_EQ(s.add_constrained(6, 5), -1); // 11 > 10 → -1
}

构建并运行主机测试

cd 01_basic_test/host_test/test_sum
idf.py --preview set-target linux   # Linux target is still experimental
idf.py build
./build/test_sum.elf

预期输出

[==========] Running 6 tests from 1 test suite.
[----------] 6 tests from TestSum
[ RUN      ] TestSum.GTestSmokeTest
[       OK ] TestSum.GTestSmokeTest (0 ms)
...
[  PASSED  ] 6 tests.

Continuous Integration

该仓库包含 GitHub Actions 工作流,在每次推送时使用官方 ESP‑IDF Docker 容器执行主机测试。无需硬件,因此 CI 在标准的 GitHub runner 上运行。

接下来是什么?

后续章节将涵盖:

  • GMock 用于通过模拟对象隔离组件。
  • CMock‑based 方法(在 ESP‑IDF 内部使用)用于模拟硬件依赖。

完整的源代码可在 github.com/aluiziotomazelli/gtest-esp-idf 获取。

0 浏览
Back to Blog

相关文章

阅读更多 »