ztest测试流程

发布于:2025-02-10 ⋅ 阅读:(76) ⋅ 点赞:(0)

ztest是Zephyr系统下的单元测试架构,可依赖硬件或模拟系统完成对代码的功能测试。

系统绑定流程

常规ztest测试架构包含如下层级:

./
├── CMakeLists.txt
├── prj.conf
├── src
│   └── main.c
└── testcase.yaml
  • CMakeLists.txt 首先被构建系统处理,它确定了项目的构建规则和源文件组织。
  • prj.conf 的配置会在编译时被应用,影响系统功能的启用和配置参数的设置(哪些参数可以使用可具体查看zephyr/driver/目录下Kconfig文件,使用语法是CONFIG_<参数名称> = )。
  • testcase.yaml 被测试框架(通常是twister)用来决定如何执行测试,包括在什么平台上运行,如何验证测试结果等。
  • main.c 中的代码在以上配置的基础上执行,执行具体的测试逻辑,并通过ztest框架报告测试结果。

基于以上配置,可启用twister或者west执行构建,并直接在终端输出测试结果。

ztest测试可针对软件和硬件,软检测试可不依赖设备树,硬件测试应当指定设备树结构。以uart_pl011驱动测试为例,并结合某个特定的 evk 开发板而言,测试启动流程应为:

source files (.dts, .dtsi)
      ↓
    预处理
      ↓ 
设备树编译器(DTC)
      ↓
build/zephyr/zephyr.dts

在嵌入式系统启动流程中,Kconfig文件和设备树文件都用来描述当前系统的配置信息,区别在于Kconfig侧重于描述软件系统的配置信息,设备树文件侧重于描述硬件系统的配置信息。我们使用

./build.sh uart_pl011_test evk

指令来完成针对evk板卡的构建,因此应当重点关于与evk有关的设备树文件以及相关驱动Kconfig文件。

查看evk.dts

/* SPDX-License-Identifier: Apache-2.0 */

/dts-v1/;

#include <evk.dtsi>

/ {
    ......

    chosen {
        ...
        zephyr,console = &uart0;
        zephyr,shell-uart = &uart0;
    };

    ......
    
    uart0: uart@C0200000 {
        compatible = "arm,pl011";
        ...
        label = "UART_0";
        current-speed = <115200>;
    };

    ......

&uart0 {
    status = "okay";
    current-speed = <115200>;
};

    ......

chosenuart0节点中明确指明了当前设备所使用的uart类型——arm,pl011,我们对uart_pl011的驱动测试也将围绕它展开。

编写main.c主测试程序,在程序开头获取设备信息并完成初始化:

#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_console), okay)  
#define UART_NODE DT_CHOSEN(zephyr_console)
#else
#define UART_NODE DT_NODELABEL(uart0)
#endif

static const struct device *uart_dev;

static void uart_setup(void)
{
    uart_dev = DEVICE_DT_GET(UART_NODE);
    zassert_not_null(uart_dev, "UART device not found");
    zassert_true(device_is_ready(uart_dev), "UART device not ready");
}
  • DT_NODE_HAS_STATUS()宏是Zephyr系统配置关键宏,用来检查设备树节点的status属性,当前在设备树中查找名为"zephyr,console"的chosen节点。
  • DT_CHOSEN()宏用来获取设备树中chosen节点下指定属性对应的节点,可实现系统级设备的配置。
  • DT_NODELABEL()宏通过节点标签label获取设备树节点。
  • zephyr,console是Zephyr系统中的一个特殊的chosen节点属性,用于指定系统的主控制台设备。

以上宏的定义可在include/devicetree.hinclude/device.h中查看。而现在的程序则实现了对设备信息的获取。

prj.conf中声明:

CONFIG_UART_PL011=y

启用uart_pl011驱动程序,告诉构建系统需要编译和链接uart_pl011驱动代码并启动相关的依赖项,激活设备树支持。

而来到uart_pl011.c驱动程序本身,在其内部同样有如下设备定义:

DEVICE_DT_INST_DEFINE(0,
                      &pl011_init,
                      NULL,
                      &pl011_data_port_0,
                      &pl011_cfg_port_0, PRE_KERNEL_1,
                      CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
                      &pl011_driver_api);

综上所述,为了实现测试程序与uart_pl011驱动的联系,并保证我们的确是在针对evk开发板的uart_pl011驱动进行的测试,我们的程序执行了如下流程:

  1. 构建系统首先检查prj.conf中的CONFIG_UART_PL011=y,决定编译uart_pl011驱动。
  2. 设备树编译器解析.dts文件,识别compatible = "arm,pl011"属性,将这个设备与uart_pl011驱动匹配。
  3. 系统启动时,驱动程序的DEVICE_DT_INST_DEFINE创建设备实例,并注册到Zephyr的设备管理系统。
  4. 当测试代码main.c通过DEVICE_DT_GET获取设备时,Zephyr的设备管理系统根据设备树信息返回正确的设备实例。

以上流程环环相扣,缺一不可。
在这里插入图片描述

在编译过后,系统会自动生成一个新的build文件夹,并生成新的zephyr.dts设备树文件,可在其中查看测试节点:

uart0: uart@C0200000 {
        compatible = "arm,pl011";
        reg = < 0xc0200000 0x4c >;
        clocks = < &sysclk >;
        interrupts = < 0xda 0x2 >;
        status = "okay";
        label = "UART_0";
        current-speed = < 0x1c200 >;
    };

表明本次测试的确在测试pl011驱动。

测试程序解析

Zephyr2.7.0的ztest测试架构依赖如下构成:

/* 2.7.0版本按照当前引入头文件的方式。3.7.0则采用 #include <zephyr/ztest.h> 的方式 */
#include <ztest.h> 

// 声明测试用例
void test_case_1(void) {
    zassert_true(1, "Test case 1 failed.");
}

void test_case_2(void) {
    zassert_equal(2, 2, "Test case 2 failed.");
}

// 定义 test_main 函数
void test_main(void) {
    // 定义一个测试套件并注册测试用例
    ztest_test_suite(my_test_suite,
        ztest_unit_test(test_case_1),
        ztest_unit_test(test_case_2)
    );

    // 运行测试套件
    ztest_run_test_suite(my_test_suite);
}

在开发程序时,每个测试项都可以被单独定义成一个测试函数,我们将待测模块的API引入测试函数中,并结合zassert_*宏来进行断言检查,用来判断模块是否符合设计需求。

在测试模块结尾,设计test_main模块用来作为整个测试程序的入口,在这其中:

  1. ztest_test_suite:用于定义一个测试套件,并将多个测试用例注册到该套件中。
  2. ztest_run_test_suite:运行指定的测试套件。

注意二者层级关系,ztest_test_suite(...ztest_run_test_suite...)

Zephyr提供诸多zassert宏用来进行检验,例如:

  • zassert_true(cond, ...)断言条件 cond 为真。如果为假,则测试失败。
  • zassert_false(cond, ...)断言条件 cond 为假。如果为真,则测试失败。
  • zassert_equal(a, b, ...)断言值 a 等于值 b。如果不相等,则测试失败。
  • zassert_not_equal(a, b, ...)断言值 a 不等于值 b。如果相等,则测试失败。

可参考:Zephyr API Documentation: Ztest assertion macros


网站公告

今日签到

点亮在社区的每一天
去签到