Zephyr Twister测试框架完全指南

Zephyr Twister测试框架完全指南

引言

在嵌入式系统开发中,测试是确保代码质量和可靠性的关键环节。Zephyr RTOS提供了一套强大的测试框架------Twister,它能够自动发现、编译、运行和报告测试结果,大大简化了测试流程。

本文将详细介绍Twister测试框架的概念、功能、使用方法,帮助您建立一套完整的测试体系。


一、Twister测试框架概述

1.1 什么是Twister

Twister 是Zephyr官方提供的测试运行器(Test Runner),它是一个基于Python的自动化测试工具,负责:
#mermaid-svg-LpSBBz4xGKC3whnt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LpSBBz4xGKC3whnt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LpSBBz4xGKC3whnt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LpSBBz4xGKC3whnt .error-icon{fill:#552222;}#mermaid-svg-LpSBBz4xGKC3whnt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LpSBBz4xGKC3whnt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LpSBBz4xGKC3whnt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LpSBBz4xGKC3whnt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LpSBBz4xGKC3whnt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LpSBBz4xGKC3whnt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LpSBBz4xGKC3whnt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LpSBBz4xGKC3whnt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LpSBBz4xGKC3whnt .marker.cross{stroke:#333333;}#mermaid-svg-LpSBBz4xGKC3whnt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LpSBBz4xGKC3whnt p{margin:0;}#mermaid-svg-LpSBBz4xGKC3whnt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LpSBBz4xGKC3whnt .cluster-label text{fill:#333;}#mermaid-svg-LpSBBz4xGKC3whnt .cluster-label span{color:#333;}#mermaid-svg-LpSBBz4xGKC3whnt .cluster-label span p{background-color:transparent;}#mermaid-svg-LpSBBz4xGKC3whnt .label text,#mermaid-svg-LpSBBz4xGKC3whnt span{fill:#333;color:#333;}#mermaid-svg-LpSBBz4xGKC3whnt .node rect,#mermaid-svg-LpSBBz4xGKC3whnt .node circle,#mermaid-svg-LpSBBz4xGKC3whnt .node ellipse,#mermaid-svg-LpSBBz4xGKC3whnt .node polygon,#mermaid-svg-LpSBBz4xGKC3whnt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LpSBBz4xGKC3whnt .rough-node .label text,#mermaid-svg-LpSBBz4xGKC3whnt .node .label text,#mermaid-svg-LpSBBz4xGKC3whnt .image-shape .label,#mermaid-svg-LpSBBz4xGKC3whnt .icon-shape .label{text-anchor:middle;}#mermaid-svg-LpSBBz4xGKC3whnt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LpSBBz4xGKC3whnt .rough-node .label,#mermaid-svg-LpSBBz4xGKC3whnt .node .label,#mermaid-svg-LpSBBz4xGKC3whnt .image-shape .label,#mermaid-svg-LpSBBz4xGKC3whnt .icon-shape .label{text-align:center;}#mermaid-svg-LpSBBz4xGKC3whnt .node.clickable{cursor:pointer;}#mermaid-svg-LpSBBz4xGKC3whnt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LpSBBz4xGKC3whnt .arrowheadPath{fill:#333333;}#mermaid-svg-LpSBBz4xGKC3whnt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LpSBBz4xGKC3whnt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LpSBBz4xGKC3whnt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LpSBBz4xGKC3whnt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LpSBBz4xGKC3whnt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LpSBBz4xGKC3whnt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LpSBBz4xGKC3whnt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LpSBBz4xGKC3whnt .cluster text{fill:#333;}#mermaid-svg-LpSBBz4xGKC3whnt .cluster span{color:#333;}#mermaid-svg-LpSBBz4xGKC3whnt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LpSBBz4xGKC3whnt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LpSBBz4xGKC3whnt rect.text{fill:none;stroke-width:0;}#mermaid-svg-LpSBBz4xGKC3whnt .icon-shape,#mermaid-svg-LpSBBz4xGKC3whnt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LpSBBz4xGKC3whnt .icon-shape p,#mermaid-svg-LpSBBz4xGKC3whnt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LpSBBz4xGKC3whnt .icon-shape .label rect,#mermaid-svg-LpSBBz4xGKC3whnt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LpSBBz4xGKC3whnt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LpSBBz4xGKC3whnt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LpSBBz4xGKC3whnt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Twister
测试发现
编译测试
运行测试
结果报告
扫描仓库
解析配置
多平台编译
并行构建
QEMU运行
硬件运行
Native运行
JSON报告
Xunit报告
HTML报告

1.2 Twister的核心功能

功能 说明
自动测试发现 扫描仓库中的测试应用
多平台编译 为不同开发板编译测试
模拟器支持 QEMU、native_sim等
硬件测试 支持连接真实硬件
并行执行 多任务并行编译和测试
结果报告 生成JSON、Xunit、HTML报告
覆盖率分析 代码覆盖率统计
Pytest集成 支持Python测试框架

1.3 测试执行流程

报告生成 硬件设备 QEMU模拟器 CMake构建系统 Twister测试框架 用户 报告生成 硬件设备 QEMU模拟器 CMake构建系统 Twister测试框架 用户 #mermaid-svg-utxe7cyB2V9eMUYB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-utxe7cyB2V9eMUYB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-utxe7cyB2V9eMUYB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-utxe7cyB2V9eMUYB .error-icon{fill:#552222;}#mermaid-svg-utxe7cyB2V9eMUYB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-utxe7cyB2V9eMUYB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-utxe7cyB2V9eMUYB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-utxe7cyB2V9eMUYB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-utxe7cyB2V9eMUYB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-utxe7cyB2V9eMUYB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-utxe7cyB2V9eMUYB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-utxe7cyB2V9eMUYB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-utxe7cyB2V9eMUYB .marker.cross{stroke:#333333;}#mermaid-svg-utxe7cyB2V9eMUYB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-utxe7cyB2V9eMUYB p{margin:0;}#mermaid-svg-utxe7cyB2V9eMUYB .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-utxe7cyB2V9eMUYB text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-utxe7cyB2V9eMUYB .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-utxe7cyB2V9eMUYB .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-utxe7cyB2V9eMUYB .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-utxe7cyB2V9eMUYB .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-utxe7cyB2V9eMUYB #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-utxe7cyB2V9eMUYB .sequenceNumber{fill:white;}#mermaid-svg-utxe7cyB2V9eMUYB #sequencenumber{fill:#333;}#mermaid-svg-utxe7cyB2V9eMUYB #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-utxe7cyB2V9eMUYB .messageText{fill:#333;stroke:none;}#mermaid-svg-utxe7cyB2V9eMUYB .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-utxe7cyB2V9eMUYB .labelText,#mermaid-svg-utxe7cyB2V9eMUYB .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-utxe7cyB2V9eMUYB .loopText,#mermaid-svg-utxe7cyB2V9eMUYB .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-utxe7cyB2V9eMUYB .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-utxe7cyB2V9eMUYB .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-utxe7cyB2V9eMUYB .noteText,#mermaid-svg-utxe7cyB2V9eMUYB .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-utxe7cyB2V9eMUYB .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-utxe7cyB2V9eMUYB .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-utxe7cyB2V9eMUYB .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-utxe7cyB2V9eMUYB .actorPopupMenu{position:absolute;}#mermaid-svg-utxe7cyB2V9eMUYB .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-utxe7cyB2V9eMUYB .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-utxe7cyB2V9eMUYB .actor-man circle,#mermaid-svg-utxe7cyB2V9eMUYB line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-utxe7cyB2V9eMUYB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 运行twister命令 扫描测试应用 解析testcase.yaml 编译测试应用 生成可执行文件 启动模拟器运行 执行测试 返回结果 烧录并运行 执行测试 返回结果 生成测试报告 输出报告


二、测试配置文件详解

2.1 testcase.yaml配置文件

每个测试应用都需要一个 testcase.yaml 配置文件:

yaml 复制代码
# testcase.yaml示例

# 通用配置
common:
  # 允许的平台列表
  platform_allow:
    - qemu_x86
    - nrf52840dk_nrf52840
    - native_sim
  
  # 默认测试平台
  integration_platforms:
    - qemu_x86
  
  # 测试超时时间(秒)
  timeout: 60
  
  # 是否为慢速测试
  slow: false
  
  # 测试级别
  level: integration
  
  # 标签
  tags:
    - kernel
    - thread
  
# 测试用例定义
tests:
  # 测试名称(格式:模块.名称.子测试)
  kernel.thread.basic:
    # 测试描述
    description: "Basic thread test"
    
    # 测试标签
    tags:
      - thread
      - basic
    
    # 测试套件
    testsuite: tests/kernel/thread
    
    # 构建配置
    extra_configs:
      - CONFIG_DEBUG=y
      - CONFIG_LOG=y
    
    # 硬件要求
    hardware:
      min_flash: 32KB
      min_ram: 8KB
    
    # 测试执行方式
    harness: console
    
    # 控制台匹配模式
    harness_config:
      type: one_line
      regex:
        - "PASS"

2.2 配置字段说明

字段 说明 示例
platform_allow 允许运行的平台 qemu_x86, nrf52840dk
platform_exclude 排除的平台 stm32f4_discovery
integration_platforms CI默认测试平台 qemu_x86
timeout 测试超时时间(秒) 60
slow 是否慢速测试 false
level 测试级别 smoke/integration/full
tags 标签分类 kernel, thread
harness 测试执行方式 console, pytest, ctest
harness_config 执行器配置 type, regex
extra_configs 额外Kconfig配置 CONFIG_DEBUG=y
extra_args 额外命令行参数 --enable-asan

2.3 测试级别说明

级别 说明 执行频率
smoke 冒烟测试,快速验证核心功能 每次提交
integration 集成测试,验证模块间协作 每日构建
full 完整测试,覆盖所有场景 每周构建
acceptance 验收测试,用户场景验证 版本发布前

三、常用Twister命令

3.1 基本命令

bash 复制代码
# 运行默认测试(扫描当前目录)
./scripts/twister

# 指定测试目录
./scripts/twister -T tests/kernel

# 指定平台
./scripts/twister -p qemu_x86

# 指定多个平台
./scripts/twister -p qemu_x86 -p nrf52840dk_nrf52840

# 列出所有可用测试
./scripts/twister --list-tests

# 列出所有可用平台
./scripts/twister --list-platforms

# 查看帮助
./scripts/twister --help

3.2 并行执行

bash 复制代码
# 使用所有CPU核心
./scripts/twister -j $(nproc)

# 指定并行任务数
./scripts/twister -j 8

3.3 输出控制

bash 复制代码
# 详细输出
./scripts/twister -v

# 更详细输出
./scripts/twister -vv

# 指定输出目录
./scripts/twister -O twister-out

# 生成HTML报告
./scripts/twister --html-report

# 生成XML报告
./scripts/twister --xunit-report

3.4 过滤测试

bash 复制代码
# 按标签过滤
./scripts/twister -t kernel

# 排除标签
./scripts/twister -e slow

# 按名称过滤
./scripts/twister -s kernel.thread.basic

# 按级别过滤
./scripts/twister --level smoke

# 按平台模式过滤
./scripts/twister --platform-pattern "nrf52*"

# 只构建不运行
./scripts/twister -b

# 只运行已构建的测试
./scripts/twister --test-only

3.5 代码覆盖率

bash 复制代码
# 启用代码覆盖率
./scripts/twister --enable-coverage

# 指定覆盖率工具
./scripts/twister --enable-coverage --coverage-tool gcovr

# 指定覆盖率格式
./scripts/twister --enable-coverage --coverage-formats html

# 指定覆盖率平台
./scripts/twister --enable-coverage --coverage-platform qemu_x86

3.6 高级选项

bash 复制代码
# 运行所有测试(包括慢速测试)
./scripts/twister --all --enable-slow

# 启用地址Sanitizer
./scripts/twister --enable-asan

# 启用内存泄漏检测
./scripts/twister --enable-lsan

# 启用未定义行为检测
./scripts/twister --enable-ubsan

# 创建ROM/RAM报告
./scripts/twister --create-rom-ram-report

# 生成内存占用报告
./scripts/twister --footprint-report

# 随机打乱测试顺序
./scripts/twister --shuffle-tests

四、Ztest测试框架

4.1 Ztest概述

Ztest 是Zephyr内置的单元测试框架,与Twister配合使用。它提供了一套断言宏和测试结构:
#mermaid-svg-K1OgrvpTpSgw4FPQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-K1OgrvpTpSgw4FPQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-K1OgrvpTpSgw4FPQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-K1OgrvpTpSgw4FPQ .error-icon{fill:#552222;}#mermaid-svg-K1OgrvpTpSgw4FPQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-K1OgrvpTpSgw4FPQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-K1OgrvpTpSgw4FPQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-K1OgrvpTpSgw4FPQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-K1OgrvpTpSgw4FPQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-K1OgrvpTpSgw4FPQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-K1OgrvpTpSgw4FPQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-K1OgrvpTpSgw4FPQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-K1OgrvpTpSgw4FPQ .marker.cross{stroke:#333333;}#mermaid-svg-K1OgrvpTpSgw4FPQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-K1OgrvpTpSgw4FPQ p{margin:0;}#mermaid-svg-K1OgrvpTpSgw4FPQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-K1OgrvpTpSgw4FPQ .cluster-label text{fill:#333;}#mermaid-svg-K1OgrvpTpSgw4FPQ .cluster-label span{color:#333;}#mermaid-svg-K1OgrvpTpSgw4FPQ .cluster-label span p{background-color:transparent;}#mermaid-svg-K1OgrvpTpSgw4FPQ .label text,#mermaid-svg-K1OgrvpTpSgw4FPQ span{fill:#333;color:#333;}#mermaid-svg-K1OgrvpTpSgw4FPQ .node rect,#mermaid-svg-K1OgrvpTpSgw4FPQ .node circle,#mermaid-svg-K1OgrvpTpSgw4FPQ .node ellipse,#mermaid-svg-K1OgrvpTpSgw4FPQ .node polygon,#mermaid-svg-K1OgrvpTpSgw4FPQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-K1OgrvpTpSgw4FPQ .rough-node .label text,#mermaid-svg-K1OgrvpTpSgw4FPQ .node .label text,#mermaid-svg-K1OgrvpTpSgw4FPQ .image-shape .label,#mermaid-svg-K1OgrvpTpSgw4FPQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-K1OgrvpTpSgw4FPQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-K1OgrvpTpSgw4FPQ .rough-node .label,#mermaid-svg-K1OgrvpTpSgw4FPQ .node .label,#mermaid-svg-K1OgrvpTpSgw4FPQ .image-shape .label,#mermaid-svg-K1OgrvpTpSgw4FPQ .icon-shape .label{text-align:center;}#mermaid-svg-K1OgrvpTpSgw4FPQ .node.clickable{cursor:pointer;}#mermaid-svg-K1OgrvpTpSgw4FPQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-K1OgrvpTpSgw4FPQ .arrowheadPath{fill:#333333;}#mermaid-svg-K1OgrvpTpSgw4FPQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-K1OgrvpTpSgw4FPQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-K1OgrvpTpSgw4FPQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-K1OgrvpTpSgw4FPQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-K1OgrvpTpSgw4FPQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-K1OgrvpTpSgw4FPQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-K1OgrvpTpSgw4FPQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-K1OgrvpTpSgw4FPQ .cluster text{fill:#333;}#mermaid-svg-K1OgrvpTpSgw4FPQ .cluster span{color:#333;}#mermaid-svg-K1OgrvpTpSgw4FPQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-K1OgrvpTpSgw4FPQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-K1OgrvpTpSgw4FPQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-K1OgrvpTpSgw4FPQ .icon-shape,#mermaid-svg-K1OgrvpTpSgw4FPQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-K1OgrvpTpSgw4FPQ .icon-shape p,#mermaid-svg-K1OgrvpTpSgw4FPQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-K1OgrvpTpSgw4FPQ .icon-shape .label rect,#mermaid-svg-K1OgrvpTpSgw4FPQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-K1OgrvpTpSgw4FPQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-K1OgrvpTpSgw4FPQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-K1OgrvpTpSgw4FPQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Ztest框架
测试套件
测试用例
断言宏
Fixture
ZTEST_SUITE
setup/teardown
ZTEST
ZTEST_P
ZTEST_F
zassert_true
zassert_equal
fixture
before/after

4.2 创建测试套件

c 复制代码
#include <zephyr/ztest.h>

/* 定义测试套件 */
ZTEST_SUITE(kernel_thread_suite, NULL, NULL, NULL, NULL, NULL);

/* 添加测试用例 */
ZTEST(kernel_thread_suite, test_thread_create) {
    /* 测试线程创建 */
    k_tid_t tid;
    struct k_thread thread;
    K_THREAD_STACK_DEFINE(stack, 1024);
    
    tid = k_thread_create(&thread, stack, K_THREAD_STACK_SIZEOF(stack),
                         NULL, NULL, NULL, K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
    
    zassert_not_null(tid, "Thread creation failed");
    zassert_true(k_thread_active(&thread), "Thread should be active");
}

ZTEST(kernel_thread_suite, test_thread_sleep) {
    /* 测试线程睡眠 */
    k_ticks_t start = k_ticks_get();
    
    k_msleep(100);
    
    k_ticks_t end = k_ticks_get();
    k_ticks_t diff = end - start;
    
    zassert_true(diff >= 100, "Sleep duration too short");
}

/* 参数化测试 */
static const struct test_param {
    int input;
    int expected;
} params[] = {
    {1, 2},
    {2, 4},
    {3, 6},
};

ZTEST_P(kernel_thread_suite, test_param_example) {
    const struct test_param *p = data;
    zassert_equal(p->input * 2, p->expected, "Parameter test failed");
}

ZTEST_P_INSTANCE(kernel_thread_suite, test_param_example, 0);
ZTEST_P_INSTANCE(kernel_thread_suite, test_param_example, 1);
ZTEST_P_INSTANCE(kernel_thread_suite, test_param_example, 2);

4.3 断言宏

断言宏 说明 示例
zassert_true(cond, msg) 断言条件为真 zassert_true(ret == 0, "Failed")
zassert_false(cond, msg) 断言条件为假 zassert_false(ptr == NULL, "Null")
zassert_equal(a, b, msg) 断言相等 zassert_equal(a, b, "Not equal")
zassert_not_equal(a, b, msg) 断言不相等 zassert_not_equal(a, b, "Equal")
zassert_null(ptr, msg) 断言为空 zassert_null(ptr, "Not null")
zassert_not_null(ptr, msg) 断言不为空 zassert_not_null(ptr, "Null")
zassert_ok(ret, msg) 断言返回OK zassert_ok(ret, "Error")
zassert_in_range(val, lo, hi, msg) 断言在范围内 zassert_in_range(x, 0, 100, "Out of range")

4.4 测试Fixture

c 复制代码
#include <zephyr/ztest.h>

/* 定义fixture结构 */
struct my_fixture {
    int value;
    struct k_mutex mutex;
};

/* setup函数 - 每个测试套件运行一次 */
static void *my_suite_setup(void) {
    struct my_fixture *fixture = malloc(sizeof(struct my_fixture));
    fixture->value = 42;
    k_mutex_init(&fixture->mutex);
    return fixture;
}

/* teardown函数 */
static void my_suite_teardown(void *fixture) {
    free(fixture);
}

/* before函数 - 每个测试用例运行前 */
static void my_before(void *fixture) {
    struct my_fixture *f = fixture;
    f->value = 0;
}

/* after函数 - 每个测试用例运行后 */
static void my_after(void *fixture) {
    struct my_fixture *f = fixture;
    k_mutex_unlock(&f->mutex);
}

/* 使用fixture的测试套件 */
ZTEST_SUITE(my_suite, NULL, my_suite_setup, my_before, my_after, my_suite_teardown);

ZTEST_F(my_suite, test_with_fixture) {
    /* 使用fixture */
    fixture->value = 100;
    zassert_equal(fixture->value, 100, "Fixture value wrong");
    
    k_mutex_lock(&fixture->mutex, K_FOREVER);
    /* 测试代码 */
    k_mutex_unlock(&fixture->mutex);
}

五、Pytest集成

5.1 Pytest简介

Twister支持与Python的pytest框架集成,允许编写更复杂的测试逻辑:
#mermaid-svg-ZgWZn92YRUIYkbAd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZgWZn92YRUIYkbAd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZgWZn92YRUIYkbAd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZgWZn92YRUIYkbAd .error-icon{fill:#552222;}#mermaid-svg-ZgWZn92YRUIYkbAd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZgWZn92YRUIYkbAd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZgWZn92YRUIYkbAd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZgWZn92YRUIYkbAd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZgWZn92YRUIYkbAd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZgWZn92YRUIYkbAd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZgWZn92YRUIYkbAd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZgWZn92YRUIYkbAd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZgWZn92YRUIYkbAd .marker.cross{stroke:#333333;}#mermaid-svg-ZgWZn92YRUIYkbAd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZgWZn92YRUIYkbAd p{margin:0;}#mermaid-svg-ZgWZn92YRUIYkbAd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZgWZn92YRUIYkbAd .cluster-label text{fill:#333;}#mermaid-svg-ZgWZn92YRUIYkbAd .cluster-label span{color:#333;}#mermaid-svg-ZgWZn92YRUIYkbAd .cluster-label span p{background-color:transparent;}#mermaid-svg-ZgWZn92YRUIYkbAd .label text,#mermaid-svg-ZgWZn92YRUIYkbAd span{fill:#333;color:#333;}#mermaid-svg-ZgWZn92YRUIYkbAd .node rect,#mermaid-svg-ZgWZn92YRUIYkbAd .node circle,#mermaid-svg-ZgWZn92YRUIYkbAd .node ellipse,#mermaid-svg-ZgWZn92YRUIYkbAd .node polygon,#mermaid-svg-ZgWZn92YRUIYkbAd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZgWZn92YRUIYkbAd .rough-node .label text,#mermaid-svg-ZgWZn92YRUIYkbAd .node .label text,#mermaid-svg-ZgWZn92YRUIYkbAd .image-shape .label,#mermaid-svg-ZgWZn92YRUIYkbAd .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZgWZn92YRUIYkbAd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZgWZn92YRUIYkbAd .rough-node .label,#mermaid-svg-ZgWZn92YRUIYkbAd .node .label,#mermaid-svg-ZgWZn92YRUIYkbAd .image-shape .label,#mermaid-svg-ZgWZn92YRUIYkbAd .icon-shape .label{text-align:center;}#mermaid-svg-ZgWZn92YRUIYkbAd .node.clickable{cursor:pointer;}#mermaid-svg-ZgWZn92YRUIYkbAd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZgWZn92YRUIYkbAd .arrowheadPath{fill:#333333;}#mermaid-svg-ZgWZn92YRUIYkbAd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZgWZn92YRUIYkbAd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZgWZn92YRUIYkbAd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZgWZn92YRUIYkbAd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZgWZn92YRUIYkbAd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZgWZn92YRUIYkbAd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZgWZn92YRUIYkbAd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZgWZn92YRUIYkbAd .cluster text{fill:#333;}#mermaid-svg-ZgWZn92YRUIYkbAd .cluster span{color:#333;}#mermaid-svg-ZgWZn92YRUIYkbAd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZgWZn92YRUIYkbAd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZgWZn92YRUIYkbAd rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZgWZn92YRUIYkbAd .icon-shape,#mermaid-svg-ZgWZn92YRUIYkbAd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZgWZn92YRUIYkbAd .icon-shape p,#mermaid-svg-ZgWZn92YRUIYkbAd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZgWZn92YRUIYkbAd .icon-shape .label rect,#mermaid-svg-ZgWZn92YRUIYkbAd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZgWZn92YRUIYkbAd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZgWZn92YRUIYkbAd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZgWZn92YRUIYkbAd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Twister
pytest
Python测试代码
设备交互
外部工具
REST API
pytest-twister-harness
fixture支持

5.2 创建Pytest测试

目录结构

复制代码
test_foo/
├── pytest/
│   └── test_foo.py
├── src/
│   └── main.c
├── CMakeLists.txt
├── prj.conf
└── testcase.yaml

testcase.yaml配置

yaml 复制代码
tests:
  sample.pytest.shell:
    harness: pytest
    tags:
      - pytest
      - shell
    harness_config:
      pytest_root:
        - "pytest/test_shell.py"

pytest测试代码

python 复制代码
# pytest/test_shell.py

import pytest
from twister_harness import Shell

def test_shell_basic(dut):
    """测试shell基本功能"""
    shell = Shell(dut)
    
    # 发送命令
    result = shell.run('version')
    assert 'Zephyr' in result
    
    # 测试多个命令
    result = shell.run('kernel threads')
    assert 'main' in result
    
    # 测试错误命令
    result = shell.run('invalid_command')
    assert 'Unknown command' in result

5.3 Pytest Fixtures

Fixture 说明
dut Device Under Test对象
shell Shell交互对象
device 设备适配器

5.4 运行Pytest测试

bash 复制代码
# 运行pytest测试
./scripts/twister -T samples/subsys/testsuite/pytest/shell -p native_posix -v

# 指定pytest参数
./scripts/twister -T samples/subsys/testsuite/pytest/shell \
    -p native_posix \
    --pytest-args='-k test_shell_print_version'

六、硬件测试

6.1 硬件映射文件

yaml 复制代码
# hardware_map.yaml

devices:
  - id: nrf52840dk_1
    type: nrf52840dk
    serial: /dev/ttyACM0
    runner: nrfjprog
  
  - id: nrf52840dk_2
    type: nrf52840dk
    serial: /dev/ttyACM1
    runner: nrfjprog
  
  - id: qemu_x86
    type: qemu_x86
    runner: qemu

6.2 运行硬件测试

bash 复制代码
# 指定硬件映射文件
./scripts/twister --hardware-map hardware_map.yaml

# 指定设备串口
./scripts/twister --device-serial /dev/ttyACM0

# 指定串口波特率
./scripts/twister --device-serial-baud 115200

# 启用设备测试模式
./scripts/twister --device-testing

# 指定flash命令
./scripts/twister --flash-command "nrfjprog --program"

七、测试结果分析

7.1 报告类型

报告类型 文件 说明
JSON报告 twister.json 详细测试结果
测试计划 testplan.json 测试计划
Xunit报告 twister.xml 标准Xunit格式
HTML报告 twister.html 可视化报告
日志文件 twister.log 测试日志

7.2 JSON报告结构

json 复制代码
{
  "version": "1.0",
  "testsuites": [
    {
      "platform": "qemu_x86",
      "name": "kernel.thread.basic",
      "testcases": [
        {
          "identifier": "test_thread_create",
          "status": "passed",
          "duration": 0.5,
          "output": "PASS"
        },
        {
          "identifier": "test_thread_sleep",
          "status": "failed",
          "duration": 0.6,
          "output": "FAIL: Sleep duration too short",
          "reason": "Assertion failed"
        }
      ]
    }
  ],
  "summary": {
    "total": 2,
    "passed": 1,
    "failed": 1,
    "skipped": 0,
    "errored": 0
  }
}

7.3 测试状态说明

状态 说明
passed 测试通过
failed 测试失败
skipped 测试跳过
errored 测试错误
build_failed 构建失败
timeout 测试超时
flashed 已烧录但未运行

7.4 分析测试结果

bash 复制代码
# 查看测试摘要
./scripts/twister -M

# 查看失败的测试
./scripts/twister -M pass

# 查看所有测试详情
cat twister-out/twister.json | python3 -m json.tool

# 统计测试结果
grep -c "\"status\": \"passed\"" twister-out/twister.json
grep -c "\"status\": \"failed\"" twister-out/twister.json

八、实际案例

8.1 创建自定义测试

步骤1:创建测试目录

bash 复制代码
mkdir -p tests/my_custom_test/src

步骤2:编写测试代码

c 复制代码
// tests/my_custom_test/src/main.c

#include <zephyr/ztest.h>

ZTEST_SUITE(my_custom_suite, NULL, NULL, NULL, NULL, NULL);

ZTEST(my_custom_suite, test_addition) {
    zassert_equal(1 + 1, 2, "1+1 should be 2");
    zassert_equal(2 + 3, 5, "2+3 should be 5");
    zassert_equal(0 + 0, 0, "0+0 should be 0");
}

ZTEST(my_custom_suite, test_string) {
    const char *str = "Hello Zephyr!";
    zassert_true(strlen(str) > 0, "String should not be empty");
    zassert_equal(strcmp(str, "Hello Zephyr!"), 0, "String mismatch");
}

void main(void) {
    ztest_run_all();
}

步骤3:编写CMakeLists.txt

cmake 复制代码
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

project(my_custom_test)

target_sources(app PRIVATE src/main.c)

步骤4:编写testcase.yaml

yaml 复制代码
common:
  platform_allow:
    - qemu_x86
    - native_sim
  integration_platforms:
    - qemu_x86
  timeout: 30
  tags:
    - custom
    - example

tests:
  my_custom_test.basic:
    description: "Custom test example"
    harness: console
    harness_config:
      type: one_line
      regex:
        - "PASS"

步骤5:运行测试

bash 复制代码
./scripts/twister -T tests/my_custom_test -p qemu_x86 -v

8.2 运行内核测试

bash 复制代码
# 运行所有内核测试
./scripts/twister -T tests/kernel -p qemu_x86

# 运行特定测试
./scripts/twister -s kernel.thread.basic -p qemu_x86

# 运行多个测试套件
./scripts/twister -T tests/kernel/sched -T tests/kernel/thread -p qemu_x86

8.3 CI集成示例

yaml 复制代码
# .github/workflows/twister.yml

name: Twister Tests

on: [push, pull_request]

jobs:
  twister:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
    
    - name: Install dependencies
      run: |
        sudo apt-get update
        sudo apt-get install -y cmake ninja-build python3-pip
        pip3 install -r scripts/requirements.txt
    
    - name: Run twister
      run: |
        source zephyr-env.sh
        ./scripts/twister -T tests/kernel -p qemu_x86 -j 4 --html-report

九、常见问题与解决方案

9.1 测试发现问题

问题1:测试未被发现

bash 复制代码
# 解决:检查目录结构和配置文件
ls -la tests/my_test/
cat tests/my_test/testcase.yaml

# 确保目录包含:
# - CMakeLists.txt
# - src/main.c
# - testcase.yaml

问题2:平台不匹配

bash 复制代码
# 解决:检查platform_allow配置
grep platform_allow tests/my_test/testcase.yaml

# 确保目标平台在允许列表中

9.2 编译问题

问题1:编译失败

bash 复制代码
# 解决:查看编译日志
./scripts/twister -T tests/my_test -p qemu_x86 -v

# 或查看构建目录
cat twister-out/qemu_x86/tests/my_test/build.log

问题2:缺少依赖

bash 复制代码
# 解决:安装必要依赖
pip3 install -r scripts/requirements.txt

9.3 运行问题

问题1:QEMU未找到

bash 复制代码
# 解决:安装QEMU
sudo apt-get install qemu-system-x86

问题2:测试超时

bash 复制代码
# 解决:增加超时时间
./scripts/twister -T tests/my_test -p qemu_x86 --timeout-multiplier 2

问题3:硬件连接问题

bash 复制代码
# 解决:检查串口
ls /dev/ttyACM*

# 指定正确的串口
./scripts/twister --device-serial /dev/ttyACM0

9.4 报告问题

问题1:报告文件未生成

bash 复制代码
# 解决:检查输出目录
ls twister-out/

# 指定输出目录
./scripts/twister -O my_output_dir

问题2:HTML报告为空

bash 复制代码
# 解决:确保有测试运行
./scripts/twister --html-report -v

十、最佳实践

10.1 测试设计原则

#mermaid-svg-AQfNzZP2h1BiucNQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AQfNzZP2h1BiucNQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AQfNzZP2h1BiucNQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AQfNzZP2h1BiucNQ .error-icon{fill:#552222;}#mermaid-svg-AQfNzZP2h1BiucNQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AQfNzZP2h1BiucNQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AQfNzZP2h1BiucNQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AQfNzZP2h1BiucNQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AQfNzZP2h1BiucNQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AQfNzZP2h1BiucNQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AQfNzZP2h1BiucNQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AQfNzZP2h1BiucNQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AQfNzZP2h1BiucNQ .marker.cross{stroke:#333333;}#mermaid-svg-AQfNzZP2h1BiucNQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AQfNzZP2h1BiucNQ p{margin:0;}#mermaid-svg-AQfNzZP2h1BiucNQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-AQfNzZP2h1BiucNQ .cluster-label text{fill:#333;}#mermaid-svg-AQfNzZP2h1BiucNQ .cluster-label span{color:#333;}#mermaid-svg-AQfNzZP2h1BiucNQ .cluster-label span p{background-color:transparent;}#mermaid-svg-AQfNzZP2h1BiucNQ .label text,#mermaid-svg-AQfNzZP2h1BiucNQ span{fill:#333;color:#333;}#mermaid-svg-AQfNzZP2h1BiucNQ .node rect,#mermaid-svg-AQfNzZP2h1BiucNQ .node circle,#mermaid-svg-AQfNzZP2h1BiucNQ .node ellipse,#mermaid-svg-AQfNzZP2h1BiucNQ .node polygon,#mermaid-svg-AQfNzZP2h1BiucNQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-AQfNzZP2h1BiucNQ .rough-node .label text,#mermaid-svg-AQfNzZP2h1BiucNQ .node .label text,#mermaid-svg-AQfNzZP2h1BiucNQ .image-shape .label,#mermaid-svg-AQfNzZP2h1BiucNQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-AQfNzZP2h1BiucNQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AQfNzZP2h1BiucNQ .rough-node .label,#mermaid-svg-AQfNzZP2h1BiucNQ .node .label,#mermaid-svg-AQfNzZP2h1BiucNQ .image-shape .label,#mermaid-svg-AQfNzZP2h1BiucNQ .icon-shape .label{text-align:center;}#mermaid-svg-AQfNzZP2h1BiucNQ .node.clickable{cursor:pointer;}#mermaid-svg-AQfNzZP2h1BiucNQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-AQfNzZP2h1BiucNQ .arrowheadPath{fill:#333333;}#mermaid-svg-AQfNzZP2h1BiucNQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-AQfNzZP2h1BiucNQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-AQfNzZP2h1BiucNQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AQfNzZP2h1BiucNQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-AQfNzZP2h1BiucNQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AQfNzZP2h1BiucNQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-AQfNzZP2h1BiucNQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-AQfNzZP2h1BiucNQ .cluster text{fill:#333;}#mermaid-svg-AQfNzZP2h1BiucNQ .cluster span{color:#333;}#mermaid-svg-AQfNzZP2h1BiucNQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AQfNzZP2h1BiucNQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-AQfNzZP2h1BiucNQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-AQfNzZP2h1BiucNQ .icon-shape,#mermaid-svg-AQfNzZP2h1BiucNQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AQfNzZP2h1BiucNQ .icon-shape p,#mermaid-svg-AQfNzZP2h1BiucNQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-AQfNzZP2h1BiucNQ .icon-shape .label rect,#mermaid-svg-AQfNzZP2h1BiucNQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AQfNzZP2h1BiucNQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AQfNzZP2h1BiucNQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AQfNzZP2h1BiucNQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 测试设计
单一职责
可重复
隔离性
快速执行
一个测试一个断言
相同输入相同输出
测试间无依赖
避免长时间操作

10.2 目录结构规范

复制代码
tests/
├── kernel/
│   ├── thread/
│   │   ├── src/
│   │   │   └── main.c
│   │   ├── CMakeLists.txt
│   │   ├── prj.conf
│   │   └── testcase.yaml
│   └── sched/
│       └── ...
├── drivers/
│   └── gpio/
│       └── ...
└── subsys/
    └── bluetooth/
        └── ...

10.3 测试命名规范

bash 复制代码
# 测试名称格式:模块.功能.子功能
# 示例:
kernel.thread.basic
drivers.gpio.pin_config
subsys.bluetooth.adv

10.4 CI集成建议

场景 建议
代码提交 运行smoke级别测试
PR合并 运行integration级别测试
每日构建 运行full级别测试
发布版本 运行所有测试 + 硬件测试

10.5 性能优化

bash 复制代码
# 使用ccache加速编译
export CCACHE_DIR=~/.ccache
./scripts/twister --enable-ccache

# 并行执行
./scripts/twister -j $(nproc)

# 只运行必要测试
./scripts/twister --level smoke

# 跳过慢速测试
./scripts/twister -e slow

结束语

通过本文的详细介绍,相信您已经全面掌握了Zephyr Twister测试框架的使用方法:

知识点 内容
Twister 测试运行器,负责发现、编译、运行、报告
testcase.yaml 测试配置文件,定义平台、超时、标签等
Ztest 单元测试框架,提供断言宏和测试结构
Pytest 集成Python测试框架,支持复杂测试逻辑
硬件测试 支持连接真实硬件设备
报告 生成JSON、Xunit、HTML等格式报告

使用Twister测试框架可以帮助您:

  1. 确保代码质量:自动化测试捕获回归问题
  2. 提高开发效率:快速验证代码修改
  3. 降低发布风险:全面测试覆盖
  4. 支持持续集成:无缝集成CI流程

建议在实际项目中:

  1. 从简单的单元测试开始
  2. 逐步增加集成测试
  3. 利用Pytest编写复杂测试
  4. 在CI中运行完整测试套件

参考资料

相关推荐
dozenyaoyida1 天前
Zephyr BLE 上行链路源码拆解:一个空中报文怎么从 radio 跑到应用回调(NCS v3.2.1)
controller·嵌入式开发·ble·host·zephyr·协议栈·软链路层
dozenyaoyida3 天前
Zephyr BLE GATT Server 注册到收发调用链源码解析(NCS v3.2.1)
ble·zephyr·gatt·ble协议栈
iini1 个月前
nRF Connect SDK 开发新体验:VS Code + Claude Code + DeepSeek + Nordic MCP 全流程(蓝牙开发实例)
agent·ai编程·nrf connect sdk·zephyr·蓝牙开发·deepseek·mcp·claude code·nordic mcp
fitpolo1 个月前
详解Zephyr设备树与设备驱动模型
zephyr
乐鑫科技 Espressif1 个月前
用 AI 开发 Zephyr-IoT 应用
人工智能·物联网·esp32·乐鑫科技·zephyr
固执的你2 个月前
串口中断接收协议数据并用状态机解析_printk()打印内容
zephyr
fitpolo2 个月前
Zephyr的SPI
zephyr
toradexsh2 个月前
基于 NXP i.MX8M Plus 测试 Zephyr RTOS
arm·rtos·nxp·imx8mp·zephyr
ScilogyHunter3 个月前
Zephyr串口驱动开发及构建完全指南
驱动开发·uart·zephyr
ScilogyHunter3 个月前
Zephyr Hello World应用开发构建完全指南
zephyr·hello world