Squish、Qt Test 与 DOM 树:三者的定位与关系



这三个概念经常在 Qt 岗位的面试里被连着问,但它们并不在同一个层面上:Qt Test 是写在代码里的单元测试框架,Squish 是从外部驱动界面的自动化测试工具,DOM 树则是一种文档结构模型。放在一起讲的价值在于,它们刚好串成了「测试的两个层次」和「界面的一种通用抽象」。

一、一句话定位

  • Qt Test:Qt 自带的单元测试框架,和被测代码编译在同一个进程里,开发者用 C++ 写,验证的是类和函数的逻辑
  • Squish:Qt 公司的商业 GUI(Graphical User Interface,图形用户界面)自动化测试工具,作为独立进程 hook 被测程序 AUT(Application Under Test,被测应用),测试工程师用脚本写,验证的是完整业务流程
  • DOM 树(Document Object Model,文档对象模型):把标记文档解析成节点树的模型,Web 端是浏览器渲染的基础,Qt 端对应 QDomDocument;同时也是 Squish 定位 Web 元素的依据

二、为什么需要两层测试

先看一个具体场景:地址簿程序里,点「新建」弹出对话框,填姓名后确定,列表里多一条记录。

Qt Test 能覆盖的是其中的数据层——ContactModel::addContact() 调完以后 rowCount() 是否 +1、dataChanged 信号有没有发出来。它跑得快(毫秒级)、能进 CI(Continuous Integration,持续集成)、失败时能直接定位到哪个函数,但它管不了「按钮到底连没连上这个槽」「对话框是不是真的弹出来了」。

Squish 覆盖的正是这一段:真的启动程序、真的点按钮、真的敲键盘,然后断言界面上的表格多了一行。代价是慢(秒级到分钟级)、需要图形环境、失败原因可能是界面改版而非逻辑出错。

结论很直接:两者不是替代关系,而是金字塔的两层。大量的 Qt Test 打底保证逻辑正确,少量的 Squish 用例守住关键业务路径不被改坏。

三、核心差异对照

维度Qt TestSquish
测试层次单元 / 组件端到端 / 系统
进程关系同进程,链接被测代码跨进程,注入 hook 驱动 AUT
编写语言C++Python / JS / Perl / Ruby / Tcl
典型执行者开发者测试工程师
授权随 Qt 附带,免费商业授权,单独付费
单个用例耗时毫秒级秒级到分钟级
对界面改动的敏感度不敏感(不碰界面)敏感,靠 Object Map(对象映射表)缓解
能否发现「信号没连上」不能能

四、同一件事的两种写法

把上面那个地址簿场景写成代码,对比最直观。Qt Test 版本:

void TestContactModel::addContact() {
    ContactModel model;
    QSignalSpy spy(&model, &ContactModel::rowsInserted);

    model.addContact({"Jifang", "guo@example.com"});

    QCOMPARE(model.rowCount(), 1);
    QCOMPARE(spy.count(), 1);            // 确认信号发了
    QCOMPARE(model.index(0, 0).data().toString(), QString("Jifang"));
}

Squish 版本:

def main():
    startApplication("addressbook")
    clickButton(waitForObject(":Address Book.New_QToolButton"))
    type(waitForObject(":Forename:_QLineEdit"), "Jifang")
    clickButton(waitForObject(":Address Book - Unnamed.OK_QPushButton"))

    table = waitForObject(":Address Book.contacts_QTableWidget")
    test.compare(table.rowCount, 1)

注意 Squish 那段里 table.rowCount 是直接读 Qt 对象的属性——它靠元对象系统拿到了真实的 QTableWidget,不是在截图上数像素。这是 Squish 和图像比对类工具(SikuliX 之类)的根本区别,也是它能容忍换皮肤、改分辨率、挪控件位置的原因。

五、DOM 树在这里扮演什么角色

DOM 树本身是 W3C 的文档模型标准,把标记文本解析成节点树:

Document
└── html (Element)
    ├── head
    │   └── title
    │       └── "标题" (Text)
    └── body
        └── div id="app"

它和前两者的连接点有两处。

第一处,Squish 测 Web 应用时,定位元素走的就是 DOM。测 Qt 应用写 {type='QPushButton' text='OK'},测 Web 应用写 {tagName='BUTTON' innerText='提交'}——同一套 API,底下换了棵树。

第二处,也是更有意思的一点:DOM 树、Qt 的 QObject parent-child 树、QML 的 Item 树,本质是同一个设计思路。都是层级容器树,查找方式一一对应:

能力Web DOMQt
按标识查找getElementByIdfindChild<T*>(name)
按条件批量查找querySelectorAllfindChildren<T*>()
样式选择器CSSQSS
访问父节点parentNodeparent()
路径表达式XPathSquish 对象名表达式

理解了这层同构关系,学任意一棵树的遍历套路,另外两棵就是换个 API 名字的事。

六、怎么选

实践上的经验:

  • 业务逻辑、数据处理、算法——一律 Qt Test,进 CI 每次提交都跑
  • Model/View 的数据正确性——Qt Test 覆盖 model,view 交给 Squish 抽查
  • 关键业务流程(登录、下单、保存导出)——Squish 用例,每日或每次发版前跑
  • 纯界面细节(间距、配色)——两者都不合适,走人工验收或视觉回归工具

一个常见的误区是想用 Squish 覆盖所有场景。它的用例维护成本远高于单元测试,界面一改就得跟着调 Object Map,铺太多会让团队被测试拖住。

术语表

简称英文全称中文与说明
DOMDocument Object Model文档对象模型。把标记文档解析成节点树的 W3C 标准
AUTApplication Under Test被测应用。Squish 术语,指被 hook 并驱动的目标程序
GUIGraphical User Interface图形用户界面
CIContinuous Integration持续集成。每次提交自动构建并跑测试
—Object Map对象映射表。Squish 中符号名到控件属性组合的映射文件
—Meta-Object System元对象系统。Qt 的运行时反射机制,Squish 靠它读取控件属性
—Model/View模型/视图。Qt 的数据与展示分离架构
W3CWorld Wide Web Consortium万维网联盟。DOM 标准的制定组织
XPathXML Path LanguageXML 路径语言。用路径表达式定位树节点
CSSCascading Style Sheets层叠样式表
QSSQt Style SheetsQt 样式表。CSS 的子集
APIApplication Programming Interface应用程序编程接口

延伸阅读

这三块各自还有不少细节,分别整理了单独的文章:

  • Squish 深入:架构、对象识别与实战要点
  • Qt Test 深入:从 QCOMPARE 到数据驱动测试
  • DOM 树深入:从浏览器渲染到 QDomDocument
posted @ 2026-09-14 17:28  起飞的乌龟  阅读(25)  评论(0)    收藏  举报