Qt Quick Test模块功能及架构

Qt Quick Test 是专门为测试 QML 应用程序设计的模块,在 Qt 6.0 中得到了显著增强。

一、主要功能/使用方法

核心功能概述

  1. QML 单元测试框架

    • 提供完整的 QML 测试环境

    • 支持测试用例组织和执行

    • 包含 QML 断言函数和测试结果收集

  2. 测试类型支持

    • 组件功能测试

    • 用户界面行为测试

    • 信号和属性绑定测试

    • 可视化项渲染测试

基本使用方法

1. 创建测试文件

cpp 复制代码
// tst_example.qml
import QtQuick 2.15
import QtTest 1.15

TestCase {
    name: "ExampleTests"

    function test_math() {
        compare(1 + 1, 2, "Basic math")
    }

    function test_property() {
        var obj = createTemporaryObject(component, parent)
        verify(obj !== null, "Object created")
        compare(obj.width, 100, "Default width")
    }
}

2. 主测试文件

cpp 复制代码
// tst_main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtTest 1.15

Window {
    visible: true
    width: 400
    height: 300

    TestCase {
        id: mainTest
        name: "MainTests"
        when: windowShown

        function test_window() {
            compare(window.width, 400, "Window width")
            compare(window.height, 300, "Window height")
        }
    }
}

关键测试元素

  1. TestCase

    • 基础测试容器

    • 提供测试函数和断言方法

    • 支持异步测试

  2. SignalSpy

    • 监听信号发射

    • 记录信号发射次数和参数

  3. TestEvent

    • 模拟鼠标和键盘输入

    • 支持触摸事件模拟

主要断言方法

方法 描述
compare(actual, expected, message) 比较实际值和期望值
verify(condition, message) 验证条件为真
tryCompare(obj, prop, expected, timeout, message) 异步比较属性值
fail(message) 强制测试失败
skip(message) 跳过当前测试

高级功能

1. 异步测试

cpp 复制代码
function test_async() {
    var obj = createTemporaryObject(component, parent)
    obj.signal.connect(function() {
        // 信号处理
    })
    tryCompare(obj, "status", "ready", 1000, "Object should become ready")
}

2. 信号监测

cpp 复制代码
function test_signal() {
    var obj = createTemporaryObject(component, parent)
    var spy = createTemporaryObject(signalSpyComponent, null, {target: obj, signalName: "clicked"})
    
    mouseClick(obj)
    compare(spy.count, 1, "Signal should be emitted once")
}

3. 事件模拟

cpp 复制代码
function test_events() {
    var obj = createTemporaryObject(buttonComponent, parent)
    mouseClick(obj, 10, 10, Qt.LeftButton)
    keyClick(Qt.Key_Enter)
}

Qt 6.0 新特性

  1. 改进的组件创建

    • createTemporaryObject() 更可靠

    • 更好的内存管理

  2. 增强的事件模拟

    • 支持多点触控

    • 更精确的鼠标移动模拟

  3. 更好的调试支持

    • 详细的错误信息

    • 测试失败时的堆栈跟踪

  4. 与 C++ 测试集成

    • 可以在 C++ 测试中嵌入 QML 测试

    • 共享测试基础设施

测试执行

  1. 命令行执行

    cpp 复制代码
    qmltestrunner -input tst_example.qml
  2. 输出选项

    • -o file,xml XML 格式输出

    • -o file,txt 文本格式输出

    • -o file,lightxml 轻量级 XML 输出

  3. 测试选择

    • 按名称筛选测试用例

    • 支持通配符匹配

最佳实践

  1. 测试组织

    • 按功能模块分组测试

    • 使用有意义的测试名称

  2. 测试数据

    • 使用 JSON 文件存储测试数据

    • 考虑使用数据驱动测试

  3. 测试稳定性

    • 避免依赖绝对时间

    • 使用 tryCompare 处理异步操作

  4. CI/CD 集成

    • 生成 JUnit 格式报告

    • 与 CMake 测试集成

二、架构解析

整体架构层次

1. QML 测试接口层

  • 测试用例声明 :通过 TestCase QML 类型定义测试

  • 断言系统 :提供 compare(), verify() 等 QML 可调用方法

  • 测试控制:管理测试执行顺序和生命周期

2. C++ 核心引擎层

  • 测试运行器QQmlTestRunner 类负责调度测试执行

  • QML 引擎集成 :与 QQmlEngine 深度集成,支持组件实例化

  • 事件系统QQuickTestEvent 及相关类处理输入模拟

3. 底层适配层

  • 与 Qt Test 集成:共享基础测试设施和报告系统

  • 平台抽象:处理不同平台的输入事件差异

核心组件设计

1. TestCase 类型系统

cpp 复制代码
TestCase {
    // 测试元数据
    name: "MyTests"
    when: windowShown
    
    // 测试资源管理
    function initTestCase() {}
    function cleanupTestCase() {}
    
    // 测试函数
    function test_example() {
        compare(1+1, 2)
    }
}

2. 测试执行流程

  1. 解析阶段:加载 QML 测试文件,识别测试用例

  2. 初始化阶段 :调用 initTestCase()

  3. 执行阶段:按顺序运行测试函数

  4. 清理阶段 :调用 cleanupTestCase()

  5. 报告阶段:生成测试结果输出

3. 关键类关系

cpp 复制代码
QQmlTestRunner
├── QQmlEngine
├── QQuickTestCase
│   ├── QQuickTestEvent
│   └── QQuickTestResult
└── QTestLogger

三、事件系统架构

1. 输入事件模拟

  • 鼠标事件mouseClick(), mouseMove()

  • 键盘事件keyClick(), keyPress()

  • 触摸事件touchEvent()

2. 事件处理流程

cpp 复制代码
测试代码调用事件方法 
→ QQuickTestEvent 创建平台事件 
→ QQuickWindow 事件分发 
→ 目标 Item 处理事件
→ 测试验证结果

信号监测系统

1. SignalSpy 实现

cpp 复制代码
SignalSpy {
    target: testObject
    signalName: "statusChanged"
}

2. 工作原理

  • 使用 Qt 元对象系统动态连接信号

  • 通过槽函数记录信号触发信息

  • 提供 countsignalArguments 属性

Qt 6.0 架构改进

  1. QML 引擎优化

    • 更快的组件实例化 (createTemporaryObject)

    • 改进的垃圾回收策略

  2. 测试隔离增强

    • 每个测试用例在独立上下文中运行

    • 更好的资源清理机制

  3. 异步测试改进

    • 更精确的 tryCompare 超时控制

    • 支持 Promise 风格的异步测试

  4. 调试支持

    • 增强的错误位置报告

    • 与 Qt Creator 深度集成

执行模型

1. 测试发现

  • 扫描指定目录的 tst_*.qml 文件

  • 解析 TestCase 元素及其测试函数

2. 执行模式

  • 顺序执行:默认串行执行测试

  • 过滤执行:支持通过名称筛选测试

  • GUI 模式 :需要显示窗口的测试 (when: windowShown)

报告系统

1. 输出格式支持

  • TAP (Test Anything Protocol)

  • XML (xUnit 风格)

  • 文本 (人类可读)

  • LightXML (简化 XML)

2. 报告生成流程

cpp 复制代码
测试执行 
→ QQuickTestResult 收集结果 
→ QTestLogger 格式化输出 
→ 控制台/文件输出

扩展机制

1. 自定义断言

cpp 复制代码
function assertApproxEqual(actual, expected, tol) {
    if (Math.abs(actual - expected) > tol)
        fail("Values differ by more than " + tol)
}

2. 测试工具组件

  • 可创建可复用的测试组件

  • 支持通过 QML 组件注入测试依赖

性能优化

  1. 延迟初始化:按需创建测试对象

  2. 智能重绘:最小化不必要的界面更新

  3. 并行化准备:预编译测试 QML 文件

Qt Quick Test 的这种架构设计使其能够高效地测试 Qt Quick 应用程序,同时保持 QML 开发的自然工作流程,是 Qt 6.0 中 UI 测试的重要基础设施。