Zephyrのテストフレームワーク調査②〜はじめてのZtest〜

はじめに

Zephyrにはテストフレームワーク (Mockもあります!) が用意されています。 テストは大事です。さっさとテストを作れるようにしましょう!

docs.zephyrproject.org

何事も写経から、ということで、サンプルの写経を行っていきます。

汎用テンプレート

まずは、公式にあるテンプレートを眺めます。

#include <ztest.h>

extern void test_sometest1(void);
extern void test_sometest2(void);
#ifndef CONFIG_WHATEVER              /* Conditionally skip test_sometest3 */
void test_sometest3(void)
{
     ztest_test_skip();
}
#else
extern void test_sometest3(void);
#endif
extern void test_sometest4(void);
...

void test_main(void)
{
     ztest_test_suite(common,
                         ztest_unit_test(test_sometest1),
                         ztest_unit_test(test_sometest2),
                         ztest_unit_test(test_sometest3),
                         ztest_unit_test(test_sometest4),
                );
     ztest_run_test_suite(common);
}

このソースコードは、sanitycheckスクリプトが解析するため、ztest_test_suiteの宣言は、以下のルールに従う必要があります。

  • 1行1宣言
  • 条件実行は、ztest_test_skip()を使用

ztest_test_suiteの中にifdefマクロがあったり、1行で2つ以上のテストケースは書けません。

CMakeLists.txt

まずは、cmakeを写経します。

cmake_minimum_required(VERSION 3.8.2)
if(BOARD STREQUAL unit_testing)
    list(APPEND SOURCES src/main.c)

    include($ENV{ZEPHYR_BASE}/tests/unit/unittest.cmake)
    project(base)
else()
    include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
    project(base)

    FILE(GLOB app_sources src/*.c)
    target_sources(app PRIVATE ${app_sources})
endif()

ん?BOARDがunit_testingかどうかで処理が分岐していますね。

試しにサンプルに戻って、-DBOARD=unit_testingで実験してみます。

# at zephyr/tests/ztest/test/base/
$ mkdir build && cd $_
$ cmake -GNinja -DBOARD=unit_testing ..
$ ninja
[5/5] Linking C executable testbinary

む、何やらtestbinaryなるバイナリが出てきました。

$ ./testbinary 
Running test suite framework_tests
===================================================================
starting test - test_empty_test
PASS - test_empty_test
===================================================================
starting test - test_assert_tests
PASS - test_assert_tests
===================================================================
Test suite framework_tests succeeded
===================================================================
PROJECT EXECUTION SUCCESSFUL

いけるやん!

build.ninjaを確認すると、run-testというコマンドがあります。

$ ninja run-test
Running test suite framework_tests
===================================================================
starting test - test_empty_test
PASS - test_empty_test
===================================================================
starting test - test_assert_tests
PASS - test_assert_tests
===================================================================
Test suite framework_tests succeeded
===================================================================
PROJECT EXECUTION SUCCESSFUL

いけるやん!

特定のユニットテストだけの実行であれば、高速にテストできます。

testcase.yaml

特に言うことはないですね。

tests:
  testing.ztest:
    tags: test_practice
    type: unit
  testing.ztest.verbose_0:
    extra_args: CONF_FILE=prj_verbose_0.conf
    tags: test_practice

prj.conf

最低限、CONFIG_ZTESTが必要です。

CONFIG_ZTEST=y

src/main.c

ありきたりなテストを書いてみます。

#include <ztest.h>

static void my_first_test(void) {
    zassert_true(1, NULL);
}

void test_main(void) {
    ztest_test_suite(my_first_tests,
        ztest_unit_test(my_first_test)
        );
    
    ztest_run_test_suite(my_first_tests);
}

zassert_true()API仕様は次のとおりです。

zassert_true(cond, msg, ...)
Assert that cond is true.

Parameters
cond: Condition to check
msg: Optional message to print if the assertion fails

オプショナルなメッセージが不要な場合は、NULLにするようです(こういうの好きではないですが)。

アサーション用のAPIはいくつか用意されています。

次は、Mockを試してみたいと思います。