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中运行完整测试套件

参考资料

相关推荐
ScilogyHunter9 小时前
Zephyr串口驱动开发及构建完全指南
驱动开发·uart·zephyr
ScilogyHunter11 小时前
Zephyr Hello World应用开发构建完全指南
zephyr·hello world
ScilogyHunter1 天前
west init 命令详解
init·zephyr·west
ScilogyHunter1 天前
使用Kconfig配置Zephyr工程完全指南
kconfig·zephyr
ScilogyHunter2 天前
Zephyr设备树完全指南
zephyr
ScilogyHunter2 天前
Zephyr项目按需配置完全指南
zephyr
ScilogyHunter2 天前
Zephyr最简工程配置指南
zephyr
ScilogyHunter2 天前
Zephyr主仓库目录结构完全指南
zephyr
ScilogyHunter3 天前
Zephyr工程配置完全指南
zephyr