0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Zephyr RTOS 〜 Twister によるテスト駆動 〜

0
Last updated at Posted at 2026-09-30

1. はじめに

今回は、Zephyr 公式に採用されている Test Runner である Twister について紹介していきます。

Twister は事前に定義したテストを、複数のボード・設定に対してビルドから実行・結果判定まで自動で回す Test Runner で、Github Actions や git hooks などを利用して変更が加えられた際に検証を行う仕組みを提供しています。

本記事では、手動でビルド実行を行うための設定について紹介していきます。自動化については必要に応じて Github Actions や git hooks について別途調べて連携させてください。

Zephyr 公式の Twister についての解説は以下に記載されています。

2. Twister の役割

1. はじめに でも触れたように、Twister はあくまで Test Runner、つまりテストを駆動させるのが主な役割となります。
テスト内容そのものは、ZTest として別途提供されており、ZTest で想定内の入出力を設定し、その検証を実行し、その結果を検証・判定するのが Twister の役割となります。

この記事ではまずはその骨組みについて解説していきます。

3. Twister の設定ファイル

Twister が検出する設定ファイル名は、testcase.yaml と sample.yaml です(ただし sample.yaml非推奨)。
このファイルをテスト駆動させたいディレクトリに配置させておくことで、後述する west twister ... コマンドを使って動作させることができます。

yaml 内では大まかに sample:, common:, tests: の3つのセクションが利用できます。次章でそれぞれの役割・記述内容を説明していきます。

2026.04.12 の変更で tests.yaml も対象になり、zephyr/sample 以下のサンプルコードも sample.yaml から tests.yaml に置き換えられました。(次の v4.5.0 から適用される?)

*.yaml は OK だとして、*.yml はどうなんだ?と考えてしまいますが、*.yml は検出できないようです。

zephyr/scripts/pylib/twister/twisterlib/testplan.py
 166     TEST_DEFINITION_FILENAME = [
 167             'testcase.yaml',
 168             'tests.yaml',
 169             'sample.yaml'
 170             ]

3.1. sample セクション

sample という名前ですが、特段 sample 専用というわけではなく、そのアプリの名称と説明を記述する項目となっています。
実際の定義は下記のように、name: と description: が利用できます。

  sample:
    type: object
    properties:
      name:
        type: string
      description:
        type: string
    required: [name]
    additionalProperties: false

3.2. common / tests セクション

common: は汎用的に使いたい・関数のように複数ヶ所から参照したい場合に定義するためのセクションで、
一方 tests: は具体的に実行したいテスト内容を登録するセクションです。

common: に記述せず tests: にすべての設定を記述することも可能ですが、common: に一旦テスト内容を書いた上で、tests: からそれを参照するのがスマートです。

それぞれのセクションで利用できる項目は結構多いので、確認したい場合は以下を開いて参照してください。

実際の定義
zephyr/scripts/schemas/twister/testsuite-schema.yaml
$defs:
  scenario:
    type: object
    properties:
      arch_exclude: {}
      arch_allow: {}
      vendor_exclude:
        type: array
        items:
          type: string
      vendor_allow:
        type: array
        items:
          type: string
      testcases:
        type: array
        items:
          type: string
      build_only:
        type: boolean
      build_on_all:
        type: boolean
      depends_on: {}
      extra_args: {}
      extra_configs:
        type: array
        items:
          type: string
      extra_conf_files:
        type: array
        items:
          type: string
      extra_overlay_confs:
        type: array
        items:
          type: string
      extra_dtc_overlay_files:
        type: array
        items:
          type: string
      extra_sections: {}
      expect_reboot:
        type: boolean
      build:
        type: boolean
      required_applications:
        type: array
        items:
          type: object
          properties:
            application:
              type: string
            name:
              # deprecated: use 'application' instead
              type: string
            path:
              type: string
            platform:
              type: string
          anyOf:
            - required: [application]
            - required: [name]
          additionalProperties: false
      required_snippets:
        type: array
        items:
          type: string
      filter:
        type: string
      levels:
        type: array
        items:
          type: string
          enum: ["smoke", "unit", "integration", "acceptance", "system", "regression"]
      integration_platforms:
        type: array
        items:
          type: string
      integration_toolchains:
        type: array
        items:
          type: string
      ignore_faults:
        type: boolean
      ignore_qemu_crash:
        type: boolean
      harness:
        type: string
      sidecar:
        type: string
      sidecar_config:
        # Per-sidecar configuration, namespaced by the sidecar name so several
        # sidecars can define keys without colliding; only the block matching
        # the scenario's `sidecar:` value is consumed. The concrete per-sidecar
        # properties are filled in at load time from the registered sidecars
        # (see twisterlib.sidecars.sidecar_config_schema), so a new sidecar does
        # not have to edit this file. This placeholder validates the shape for
        # any consumer that loads the schema directly.
        type: object
      harness_config:
        type: object
        properties:
          power_measurements: {}
          shell_commands_file:
            type: string
          shell_commands:
            type: array
            items:
              type: object
              properties:
                command:
                  type: string
                expected:
                  type: string
              required: [command]
              additionalProperties: false
          display_capture_config:
            type: string
          type:
            type: string
          fixture: {}
          ordered:
            type: boolean
          pytest_root:
            type: array
            items:
              type: string
          pytest_args:
            type: array
            items:
              type: string
          pytest_dut_scope:
            type: string
            enum: ["function", "class", "module", "package", "session"]
          required_devices:
            type: array
            items:
              type: object
              properties:
                platform:
                  type: string
                fixture:
                  type: array
                  items:
                    type: string
                application:
                  type: string
                path:
                  type: string
              additionalProperties: false
          ctest_args:
            type: array
            items:
              type: string
          regex:
            type: array
            items:
              type: string
          robot_testsuite: {}
          robot_option: {}
          record:
            type: object
            properties:
              regex:
                type: array
                items:
                  type: string
              merge:
                type: boolean
              as_json:
                type: array
                items:
                  type: string
            required: [regex]
            additionalProperties: false
          bsim_exe_name:
            type: string
          tests_scripts:
            type: array
            items:
              type: string
          ztest_suite_repeat:
            type: integer
          ztest_test_repeat:
            type: integer
          ztest_test_shuffle:
            type: boolean
        additionalProperties: false
      min_ram:
        type: integer
      min_flash:
        type: integer
      modules:
        type: array
        items:
          type: string
      platform_exclude: {}
      platform_allow: {}
      platform_type:
        type: array
        items:
          type: string
          enum: ["mcu", "qemu", "sim", "unit", "native"]
      platform_key:
        type: array
        items:
          type: string
      simulation_exclude:
        type: array
        items:
          type: string
          enum:
            - qemu
            - simics
            - xt-sim
            - renode
            - nsim
            - mdb-nsim
            - tsim
            - armfvp
            - native
            - custom
      tags: {}
      timeout:
        type: integer
      toolchain_exclude: {}
      toolchain_allow: {}
      type:
        type: string
        enum: ["unit"]
      skip:
        type: boolean
      slow:
        type: boolean
      sysbuild:
        type: boolean
    additionalProperties: false

3.3. hello_world の設定

では、実際に hello_world に配置されている tests.yaml を確認してみます。

hello_world/tests.yaml
sample:
  description: Hello World sample, the simplest Zephyr
    application
  name: hello world
common:
  min_ram: 2
  min_flash: 16
  tags: introduction
  integration_platforms:
    - native_sim
  harness: console
  harness_config:
    type: one_line
    regex:
      - "Hello World! (.*)"
tests:
  sample.basic.helloworld:
    tags: introduction
  • sample: は説明したとおり、その概要とアプリケーション名を記述しています。記述は任意です。
  • tests: は項目に対してタグ付けしているだけで、動作に影響を与える項目はありません。その結果 common: に定義した内容がそのまま適用されます。tests: は必須項目です。
  • common: hello_world では以下の項目が定義されています。scenario: を使うことで複数登録でき、twister 実行時に内容を指定することもできます。なお common: に記述した内容は tests: 側に直接書くこともでき、記述は任意です。
項目 説明
min_ram RAM が最低 2KB ある MCU を対象に設定
min_flash ROM が最低 16KB ある MCU を対象に設定
tags この項目に対してタグ付けしています。twister 実行時に
platform_allow hello_world には無いですが、ここで指定したターゲットボードを検証対象と設定可能。rpi_pico などを追記可能
integration_platforms ターゲット指定の絞り込み。native_sim は Linux アプリケーションとして動作する指定
harness テスト結果の判定方法を指定。console は Linux アプリとして動作させた上で出力される文字列を判定することになります。その他 test, console, pytest, shell, gtest, ctest, robot, power, display_capture が指定できるようです
harness_config harness が console 指定だった場合に利用できる、判定方法の指定。正規表現で成否判定を行う

4. 実行

実行方法は、west コマンドが使える状態で以下のコマンドで実施します。-T には検査対象のコードや設定ファイルが配置されたディレクトリを指定します。

twister 実行方法
west twister -T zephyr/samples/hello_world/
twister 実行結果
$ west twister -T zephyr/samples/hello_world/
INFO    - Using Ninja..
INFO    - Zephyr version: v4.4.0
INFO    - Using 'zephyr/gnu' toolchain variant.
INFO    - Selecting default platforms per testsuite scenario
INFO    - Building initial testsuite list...
INFO    - Built testsuite list in 0.00 seconds
INFO    - Writing JSON report /home/taka/Projects/zephyr/official/zephyr/samples/hello_world/twister-out/testplan.json
INFO    - JOBS: 16
INFO    - Adding tasks to the queue...
INFO    - Added initial list of jobs to queue
INFO    - Total complete:   30/  30  100%  built (not run):    0, filtered:   18, failed:    0, error:    0
INFO    - 1 test scenarios (48 configurations) selected, 18 configurations filtered (18 by static filter, 0 at runtime).
INFO    - 30 of 30 executed test configurations passed (100.00%), 0 built (not run), 0 failed, 0 errored, with no warnings in 56.41 seconds.
INFO    - 30 of 30 executed test cases passed (100.00%) on 30 out of total 1473 platforms (2.04%).
INFO    - 30 test configurations executed on platforms, 0 test configurations were only built.
INFO    - Saving reports...
INFO    - Writing JSON report /home/taka/Projects/zephyr/official/zephyr/samples/hello_world/twister-out/twister.json
INFO    - Writing xunit report /home/taka/Projects/zephyr/official/zephyr/samples/hello_world/twister-out/twister.xml...
INFO    - Writing xunit report /home/taka/Projects/zephyr/official/zephyr/samples/hello_world/twister-out/twister_report.xml...
INFO    - Run completed

実行が終わると twister-out というディレクトリに結果がファイルとして出力されます。

出力結果
$ ls zephyr/samples/hello_world/twister-out/
mps2_an385                           qemu_or1k_qemu_or1k
mps2_an386                           qemu_riscv32_qemu_virt_riscv32
mps2_an521_cpu0                      qemu_riscv32_qemu_virt_riscv32_smp
mps3_corstone300_an547               qemu_riscv32e_qemu_virt_riscv32e
native_sim_native                    qemu_riscv64_qemu_virt_riscv64
qemu_arc_qemu_arc_em                 qemu_riscv64_qemu_virt_riscv64_smp
qemu_arc_qemu_arc_hs                 qemu_rx_r5f562n8
qemu_arc_qemu_arc_hs5x               qemu_x86_64_atom
qemu_arc_qemu_arc_hs6x               qemu_x86_atom
qemu_arc_qemu_arc_hs_xip             qemu_xtensa_dc233c
qemu_cortex_a53_qemu_cortex_a53      qemu_xtensa_dc233c_mmu
qemu_cortex_a53_qemu_cortex_a53_smp  qemu_xtensa_sample_controller32_mpu
qemu_cortex_a9_xc7z007s              testplan.json
qemu_cortex_m0_nrf51822              twister.json
qemu_cortex_r5_zynqmp_rpu            twister.log
qemu_leon3_leon3                     twister.xml
qemu_malta_qemu_malta                twister_report.xml
qemu_malta_qemu_malta_be             twister_suite_report.xml

5. まとめ

今回、Zephyr が採用・提供している Test Runner である Twister について紹介しました。
これ単体でもビルドが通るのか、期待した printk() が出力されるのか等の検証は可能ですが、さらに Zephyr が提供している ZTest を用いることで、より詳細に検証が行えるようになります。

この ZTest についてはまた別途投稿していきたいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?