当前位置: 首页 > article >正文

Qt Test功能及架构

Qt Test 是 Qt 框架中的单元测试模块,在 Qt 6.0 中提供了全面的测试功能。

一、主要功能

核心功能

1. 单元测试框架

  • 提供完整的单元测试基础设施

  • 支持测试用例、测试套件的组织和执行

  • 包含断言宏和测试结果收集

2. 测试类型支持

  • 单元测试:对单个函数或类的测试

  • GUI 测试:对图形用户界面的测试

  • 基准测试:性能测量和比较

  • 数据驱动测试:使用不同输入数据运行相同测试逻辑

主要组件

1. 测试宏

QVERIFY(condition)      // 验证条件为真
QCOMPARE(actual, expected) // 比较实际值和期望值
QTRY_VERIFY(condition)  // 异步验证,带超时
QTEST_MAIN(TestClass)   // 生成main()函数

2. 测试类

  • QTest:核心测试功能命名空间

  • QSignalSpy:用于监视信号发射

  • QTestEventList:模拟用户输入事件

Qt 6.0 中的新特性

  1. 改进的 CMake 集成:更好地支持现代 CMake 项目结构

  2. 增强的基准测试:更精确的计时和统计功能

  3. 更好的 Qt Quick 测试支持:改进对 QML 应用的测试能力

  4. C++17 兼容性:充分利用现代 C++ 特性

基本测试示例

#include <QtTest>class TestMath : public QObject
{Q_OBJECT
private slots:void testAddition(){QCOMPARE(1 + 1, 2);}void testString_data(){QTest::addColumn<QString>("string");QTest::addColumn<bool>("result");QTest::newRow("empty") << "" << true;QTest::newRow("non-empty") << "test" << false;}void testString(){QFETCH(QString, string);QFETCH(bool, result);QCOMPARE(string.isEmpty(), result);}
};QTEST_MAIN(TestMath)
#include "testmath.moc"

高级功能

  1. GUI 测试

    • 模拟鼠标点击、键盘输入

    • 验证窗口属性和小部件状态

  2. 基准测试

    void benchmarkLoop()
    {QString str;QBENCHMARK {str = "test";str.append("123");}
    }
  3. 异步测试

    • 使用 QSignalSpy 等待信号

    • QTRY_VERIFY 和 QTRY_COMPARE 宏

  4. 测试覆盖率

    • 与覆盖率工具(如 gcov、lcov)集成

    • 支持生成覆盖率报告

测试执行

  1. 命令行执行

    ./testname -o result.xml,xunit
  2. 输出格式

    • 纯文本

    • XML(兼容xUnit)

    • CSV

    • LightXML

  3. 测试选择

    • 按测试函数名选择执行

    • 按数据行选择执行

与 CI/CD 集成

  • 支持主流持续集成系统

  • 可生成机器可读的测试结果

  • 可与 CMake/CTest 集成

Qt 6.0 的 Test 模块为 Qt 应用程序提供了全面的测试解决方案,从简单的单元测试到复杂的 GUI 和性能测试,帮助开发者构建高质量的 Qt 应用程序。

二、架构解析

1. 整体架构概览

Qt Test 模块的架构可分为以下几个核心层次:

层级功能关键组件
测试声明层定义测试用例、数据驱动测试QTEST_MAINQ_DECLARE_TESTQTEST_* 宏
测试执行引擎运行测试、管理测试生命周期QTest::qExec()QTestEventLoop
断言与验证提供测试断言和结果检查QVERIFYQCOMPAREQTRY_* 宏
模拟与事件GUI 测试、信号监测、事件模拟QSignalSpyQTestEventList
基准测试性能测量与统计QBENCHMARKQTest::setBenchmarkResult()
输出与报告生成测试报告(文本、XML、JUnit)QTestLogQTestResult

2. 核心组件详解

(1) 测试声明与运行

  • QTEST_MAIN 宏:自动生成 main() 函数,调用 QTest::qExec() 执行测试。

  • 测试类:继承 QObject,并使用 Q_OBJECT 宏,测试函数声明为 private slots

  • 数据驱动测试:使用 QTest::addColumn() 和 QTest::newRow() 定义测试数据表。

#include <QtTest>class TestExample : public QObject {Q_OBJECT
private slots:void testCase1() { QVERIFY(1 + 1 == 2); }void testCase2_data();void testCase2();
};void TestExample::testCase2_data() {QTest::addColumn<int>("input");QTest::addColumn<int>("expected");QTest::newRow("case1") << 1 << 2;QTest::newRow("case2") << 2 << 4;
}void TestExample::testCase2() {QFETCH(int, input);QFETCH(int, expected);QCOMPARE(input * 2, expected);
}QTEST_MAIN(TestExample)
#include "testexample.moc"

(2) 测试执行引擎

  • QTest::qExec():核心测试运行器,管理测试生命周期(initTestCase()cleanupTestCase())。

  • 事件循环集成:支持异步测试(QTestEventLoop)。

  • 测试选择:支持按名称筛选测试用例(./test -functions)。


(3) 断言与验证

用途
QVERIFY(cond)检查条件是否为 true
QCOMPARE(actual, expected)比较实际值和期望值
QTRY_VERIFY(cond)异步等待条件成立(带超时)
QTRY_COMPARE(actual, expected)异步比较(带超时)
QFAIL(msg)强制测试失败

(4) 模拟与事件

  • QSignalSpy:监听信号发射次数及参数。

  • QTestEventList:模拟鼠标、键盘事件。

// 监听信号
QSignalSpy spy(button, &QPushButton::clicked);
QTest::mouseClick(button, Qt::LeftButton);
QCOMPARE(spy.count(), 1);// 模拟键盘输入
QTest::keyClick(lineEdit, Qt::Key_A);
QCOMPARE(lineEdit->text(), "A");

(5) 基准测试

  • QBENCHMARK:测量代码执行时间。

  • QTest::setBenchmarkResult():自定义基准结果。

void BenchmarkExample::testStringConcat() {QString str;QBENCHMARK {str += "test";}QVERIFY(!str.isEmpty());
}

(6) 输出与报告

  • 支持多种格式

    • 文本(默认)

    • XML(-o result.xml,xunit

    • JUnit(CI/CD 集成)

  • 日志控制

    • -silent(静默模式)

    • -v1/-v2(详细输出)


3. Qt 6.0 的改进

  1. CMake 集成优化

    • 使用 find_package(Qt6 REQUIRED COMPONENTS Test) 引入测试模块。

    • 支持 qt_add_test() 自动注册测试到 CTest。

  2. C++17 支持

    • 更高效的模板元编程优化。

    • 改进的 QSignalSpy 实现。

  3. Qt Quick 测试增强

    • 更好的 QML 单元测试支持(QUICK_TEST_MAIN)。


4. 架构总结

Qt Test 模块采用 分层设计

  1. 声明层(测试宏、数据驱动)

  2. 执行层QTest::qExec、事件循环)

  3. 验证层(断言、信号监测)

  4. 输出层(日志、报告)

其核心优势:
✔ 轻量级,无需额外依赖
✔ 支持 GUI 测试(鼠标/键盘模拟)
✔ 集成 Qt 信号槽机制QSignalSpy
✔ 兼容 CI/CD(XML/JUnit 输出)

适用于:

  • 单元测试(C++/QML)

  • GUI 自动化测试

  • 性能基准测试(QBENCHMARK

Qt 6.0 进一步优化了其与现代构建系统(CMake)的集成,并提升了测试性能和灵活性。

相关文章:

Qt Test功能及架构

Qt Test 是 Qt 框架中的单元测试模块&#xff0c;在 Qt 6.0 中提供了全面的测试功能。 一、主要功能 核心功能 1. 单元测试框架 提供完整的单元测试基础设施 支持测试用例、测试套件的组织和执行 包含断言宏和测试结果收集 2. 测试类型支持 单元测试&#xff1a;对单个函…...

图像处理、图像分析和图像理解的定义、联系与区别

1. 定义 图像处理&#xff08;Image Processing&#xff09; 图像处理是低层操作&#xff0c;主要针对像素级的图像数据进行加工&#xff0c;目的是改善图像质量或为后续分析做准备。 典型任务&#xff1a;去噪、增强&#xff08;如对比度调整&#xff09;、锐化、边缘检测、图…...

【Java开发日记】说一说 SpringBoot 中 CommandLineRunner

目录 1、CommandLineRunner SpringBoot中CommandLineRunner的作用 简单例子 多个类实现CommandLineRunner接口执行顺序的保证 通过实现Ordered接口实现控制执行顺序 通过Order注解实现控制执行顺序 Order 作用 2、ApplicationRunner 3、传递参数 4、源码跟踪 run()方…...

全面理解 Linux 内核性能问题:分类、实战与调优策略

在 Linux 系统&#xff08;特别是嵌入式或服务器环境&#xff09;中&#xff0c;性能问题往往错综复杂、表象多变。只有对常见性能问题进行系统归类、理解其症状与根源&#xff0c;才能有效定位和解决。本文将围绕八大类核心性能问题&#xff0c;结合实战示例&#xff0c;逐类分…...

算法-多条件排序

1、数对排序的使用 pair<ll,ll> a[31];//cmp为比较规则 ll cmp(pair<ll,ll>a,pair<ll,ll>b){if(a.first!b.first)return a.first>b.first;else return a.second<b.second; }//按照比较规则进行排序 sort(a1,a31,cmp); 2、具体例题 输入样例&#xff1…...

DelayQueue、ScheduledThreadPoolExecutor 和 PriorityBlockingQueue :怎么利用堆实现定时任务

DelayQueue DelayQueue 的最大亮点&#xff1a; 并不是简单全局锁的“单调队列”实现&#xff0c;而是用Leader-Follower 模式极大减少了线程唤醒的开销。插入与唤醒、等待与 leader 变更&#xff0c;都通过巧妙的锁和条件变量组合完成。 如果只关注“线程安全的优先队列全局…...

Kafka 消息模式实战:从简单队列到流处理(二)

四、Kafka 流处理实战 4.1 Kafka Streams 简介 Kafka Streams 是 Kafka 提供的流处理库&#xff0c;它为开发者提供了一套简洁而强大的 API&#xff0c;用于构建实时流处理应用程序。Kafka Streams 基于 Kafka 的高吞吐量、分布式和容错特性&#xff0c;能够处理大规模的实时…...

大数据(2) 大数据处理架构Hadoop

一、Hadoop简介 1.定义 Hadoop 是一个开源的分布式计算框架&#xff0c;由 Apache 基金会开发&#xff0c;用于处理海量数据&#xff0c;具备高可靠性、高扩展性和高容错性。它主要由两个核心模块组成&#xff1a; HDFS&#xff08;Hadoop Distributed File System&#xff09…...

【Kotlin】注解反射扩展

文章目录 注解用法反射类引用 扩展扩展函数的作用域成员方法优先级总高于扩展函数 被滥用的扩展函数扩展属性静态扩展 标准库中的扩展函数 使用 T.also 函数交换两个变量sNullOrEmpty | isNullOrBlankwith函数repeat函数 调度方式对扩展函数的影响静态与动态调度扩展函数始终静…...

固定ip和非固定ip的区别是什么?如何固定ip地址

在互联网中&#xff0c;我们常会接触到固定IP和非固定IP的概念。它们究竟有何不同&#xff1f;如何固定IP地址&#xff1f;让我们一起来探究这个问题。 一、固定IP和非固定IP的区别是什么 固定IP&#xff08;静态IP&#xff09;和非固定IP&#xff08;动态IP&#xff09;是两种…...

升级centos 7.9内核到 5.4.x

前面是指南&#xff0c;后面是工作日志。 wget http://mirrors.coreix.net/elrepo-archive-archive/kernel/el7/x86_64/RPMS/kernel-lt-devel-5.4.225-1.el7.elrepo.x86_64.rpm wget http://mirrors.coreix.net/elrepo-archive-archive/kernel/el7/x86_64/RPMS/kernel-lt-5.4.2…...

Nginx 安全设置配置

1、增加header公共文件 文件地址&#xff1a;/etc/nginx/conf.d/security_headers.conf # XSS防护配置add_header X-XSS-Protection "1; modeblock" always; # 其他安全配置add_header X-Content-Type-Options "nosniff";add_header X-Frame-Options &qu…...

协程的常用阻塞函数

以下是一些常见的阻塞函数示例&#xff1a; 1. **Thread.sleep()** 阻塞当前线程一段时间。 kotlin Thread.sleep(1000) // 阻塞线程 1 秒 2. **InputStream.read()** 从输入流中读取数据时会阻塞&#xff0c;直到有数据可用或流结束。 kotlin val inputStream FileInputStre…...

探索NoSQL注入的奥秘:如何消除MongoDB查询中的前置与后置条件

随着互联网技术的飞速发展&#xff0c;数据库作为信息存储与管理的核心&#xff0c;其安全性问题日益凸显。近年来&#xff0c;NoSQL数据库因其灵活性和高性能逐渐成为许多企业的首选&#xff0c;其中MongoDB以其文档存储和JSON-like查询语言在开发社区中广受欢迎。然而&#x…...

使用矩阵乘法+线段树解决区间历史和问题的一种通用解法

文章目录 前言P8868 [NOIP2022] 比赛CF1824DP9990/2020 ICPC EcFinal G 前言 一般解决普通的区间历史和&#xff0c;只需要定义辅助 c h s − t ⋅ a chs-t\cdot a chs−t⋅a&#xff0c; h s hs hs是历史和&#xff0c; a a a是区间和&#xff0c; t t t是时间戳&#xff0c…...

React Navive初识

文章目录 搭建开发环境安装 Node、homebrew、Watchman安装 Node安装 homebrew安装 watchman 安装 React Native 的命令行工具&#xff08;react-native-cli&#xff09;创建新项目编译并运行 React Native 应用在 ios 模拟器上运行 调试访问 App 内的开发菜单 搭建开发环境 在…...

scss(sass)中 的使用说明

在 SCSS&#xff08;Sass&#xff09;中&#xff0c;& 符号是一个父选择器引用&#xff0c;它代表当前嵌套规则的外层选择器。主要用途如下&#xff1a; 1. 连接伪类/伪元素 scss 复制 下载 .button {background: blue;&:hover { // 相当于 .button:hoverbackgrou…...

如何从浏览器中导出网站证书

以导出 GitHub 证书为例&#xff0c;点击 小锁 点击 导出 注意&#xff1a;这里需要根据你想要证书格式手动加上后缀名&#xff0c;我的是加 .crt 双击文件打开...

低功耗MQTT物联网架构Java实现揭秘

文章目录 一、引言二、相关技术概述2.1 物联网概述2.2 MQTT协议java三、基于MQTT的Iot物联网架构设计3.1 架构总体设计3.2 MQTT代理服务器选择3.3 物联网设备设计3.4 应用服务器设计四、基于MQTT的Iot物联网架构的Java实现4.1 开发环境搭建4.2 MQTT客户端实现4.3 应用服务器实现…...

总结HTML中的文本标签

总结HTML中的文本标签 文章目录 总结HTML中的文本标签引言一、标题标签&#xff08;h1 - h6&#xff09;语法示例使用建议 二、段落标签&#xff08;p&#xff09;语法示例使用建议 三、文本节点标签&#xff08;span&#xff09;语法示例使用建议 四、粗体标签&#xff08;b&a…...

python版若依框架开发:前端开发规范

python版若依框架开发 从0起步,扬帆起航。 python版若依部署代码生成指南,迅速落地CURD!项目结构解析前端开发规范文章目录 python版若依框架开发新增 view新增 api新增组件新增样式引⼊依赖新增 view 在 @/views文件下 创建对应的文件夹,一般性一个路由对应⼀个文件, 该…...

AI推理服务的高可用架构设计

AI推理服务的高可用架构设计 在传统业务系统中,高可用架构主要关注服务冗余、数据库容灾、限流熔断等通用能力。而在AI系统中,尤其是大模型推理服务场景下,高可用架构面临更加复杂的挑战,如推理延迟敏感性、GPU资源稀缺性、模型版本切换频繁等问题。本节将专门探讨如何构建…...

GPU集群故障分析:大型AI训练中的硬件问题与影响

GPU集群故障分析&#xff1a;大型AI训练中的硬件问题与影响 核心问题 在大型AI计算集群&#xff08;如使用上千块GPU卡训练大模型&#xff09;中&#xff1a; GPU硬件会出哪些毛病&#xff1f;这些问题发生的频率、严重程度如何&#xff1f;最终对AI训练任务有什么影响&#…...

ideal2022.3.1版本编译项目报java: OutOfMemoryError: insufficient memory

最近换了新电脑&#xff0c;用新电脑拉项目配置后&#xff0c;启动时报错&#xff0c;错误描述 idea 启动Springboot项目在编译阶段报错&#xff1a;java: OutOfMemoryError: insufficient memory 2. 处理方案 修改VM参数&#xff0c;分配更多内存 ❌ 刚刚开始以为时JVM内存设置…...

centos7编译安装LNMP架构

一、LNMP概念 LNMP架构是一种常见的网站服务器架构&#xff0c;由Linux操作系统、Nginx Web服务器、MySQL数据库和PHP后端脚本语言组成。 1 用户请求&#xff1a;用户通过浏览器输入网址&#xff0c;请求发送到Nginx Web服务器。 2 Nginx处理&#xff1a;Nginx接收请求后&…...

接口限频算法:漏桶算法、令牌桶算法、滑动窗口算法

文章目录 限频三大算法对比与选型建议一、漏桶算法&#xff08;Leaky Bucket Algorithm&#xff09;1.核心原理2.实现3.为什么要限制漏桶容量4.优缺点分析 二、令牌桶算法&#xff08;Token Bucket Algorithm&#xff09;1.核心原理2.实现&#xff08;1&#xff09;单机实现&am…...

Spring Boot 3.3 + MyBatis 基础教程:从入门到实践

Spring Boot 3.3 MyBatis 基础教程&#xff1a;从入门到实践 在当今的Java开发领域&#xff0c;Spring Boot和MyBatis是构建高效、可维护的后端应用的两个强大工具。Spring Boot简化了Spring应用的初始搭建和开发过程&#xff0c;而MyBatis则提供了一种灵活的ORM&#xff08;…...

征文投稿:如何写一份实用的技术文档?——以软件配置为例

&#x1f4dd; 征文投稿&#xff1a;如何写一份实用的技术文档&#xff1f;——以软件配置为例 目录 [TOC](目录)&#x1f9ed; 技术文档是通往成功的“说明书”&#x1f4a1; 一、明确目标读者&#xff1a;他们需要什么&#xff1f;&#x1f4cb; 二、结构清晰&#xff1a;让读…...

【后端】RPC

不定期更新。 定义 RPC 是 Remote Procedure Call 的缩写&#xff0c;中文通常翻译为远程过程调用。作用 简化分布式系统开发。实现微服务架构&#xff0c;便于模块化、复用。提高系统性能和可伸缩性。提供高性能通信、负载均衡、容错重试机制。 在现代分布式系统、微服务架构…...

详细讲解Flutter GetX的使用

Flutter GetX 框架详解&#xff1a;状态管理、路由与依赖注入 GetX 是 Flutter 生态中一款强大且轻量级的全功能框架&#xff0c;集成了状态管理、路由管理和依赖注入三大核心功能。其设计理念是简洁高效&#xff0c;通过最小的代码实现最大的功能&#xff0c;特别适合快速开发…...