使用 Xnee 测试应用程序
Xnee 可以记录用户在会话期间的操作,然后重放这些操作。通过在测试程序时记录会话,Xnee 可以自动为您稍后测试程序。这些测试会话可以在每次发布前或每晚重放,以确保程序的质量。它真的像听起来那么容易吗? 几乎如此。
Xnee 不仅测试 GUI。您还可以通过制作一些测试脚本来测试命令行程序,这些脚本测试命令行程序的所有选项并分析结果。Xnee 还被用于测试在具有大量瘦客户端的大型网络上发送了多少流量。如果您想同时在多台机器上测试相同的情况,则添加了对将事件分发到多个显示器的支持。除了测试程序外,Xnee 还用于演示程序。在这种情况下,Xnee 充当耐心的演示者,一遍又一遍地做同样的工作而没有抱怨。
1997 年,Henric Johansson 和我撰写了关于记录和重放 X 事件的硕士论文。我们为一个瑞典公司实施了一个非免费的记录器和重放器,供其内部使用。找到工作后,我经常缺少用于 X11 的免费测试程序,因此我决定利用论文中获得的经验自己实现一个。Xnee 项目于 1999 年夏天启动,并从一开始就获得了 GPL 许可。2002 年 11 月,发布了 1.0 版本,到 2003 年 2 月底,Xnee 被称为 GNU 软件包。
在我们继续介绍 Xnee 之前,这个关于 X 的简短介绍解释了本文中使用的许多术语。X 是适用于各种平台的基于窗口的用户界面系统。X 服务器是一个处理所有硬件并实际在屏幕上进行绘制的程序。在 GNU/Linux 系统上,XFree86 是最常用的 X 服务器。X 程序被称为客户端;示例包括 xterm 和 Galeon。客户端使用 X 协议与 X 服务器通信。
在本文中,我们专注于用于在 X 服务器及其客户端之间发送信息的数据包。这些数据包称为事件、请求、回复和错误,在这里统称为协议数据。以下列表显示了 X11 协议数据描述
请求由客户端发送到服务器。请求服务器执行某些操作或发送某些信息。
回复由服务器发送到客户端,作为对来自客户端的某些请求的响应。并非所有请求都会产生回复。
事件由服务器发送到客户端,以通知客户端用户输入或已发生客户端可能想要执行某些操作的事情,例如,客户端失去焦点。
错误在请求无效时由服务器发送到客户端。
这里最有趣的事情是,每次用户使用鼠标或键盘与计算机交互时,X 服务器都会向相应的客户端发送一个或多个事件。其中一些事件直接来自用户输入。这些事件被称为设备事件。设备事件包括 ButtonPress、ButtonRelease、MotionNotify、KeyPress 和 KeyRelease。如果我们可以在会话期间记录所有这些事件,我们将拥有用户执行的所有操作的完整描述。如果我们有一个机器人可以读取这些事件(如果它们被打印到文件或纸上),那么机器人就可以像用户在记录时一样与系统交互,我们就会拥有一个测试机器人。或者,更好的是,如果我们有支持伪造这些事件,我们将拥有一个由软件制成的测试机器人。幸运的是,X 中存在对记录和重放的支持。
要记录 X 协议数据,我们可以使用扩展 RECORD 或 XTrap。还有其他方法可以完成记录,例如嗅探 X 套接字,但我们将重点关注 RECORD,因为它正是 Xnee 使用的。要重放事件,我们可以同时使用 XTest 扩展和 RECORD 扩展。在重放期间,RECORD 扩展用于同步重放时发生的情况与会话记录时发生的情况。
RECORD 扩展将客户端和服务器之间发送的数据副本发送给请求它的客户端。使用 RECORD 扩展,Xnee 可以记录用户想要的所有协议数据,并将其保存到文件中以供以后重放。
XTest 扩展可以重现或伪造所有设备事件。此扩展使 Xnee 可以伪造用户操作,例如移动指针、按下和释放按键或按下和释放按钮。不能重放其他数据。
Xnee 是一个 GNU 软件包,可以在 Xnee 主页上找到源代码。下载最新的源代码;截至撰写本文时,最新版本为 1.0.6。解压软件包,然后配置、构建和安装它
tar zxvf xnee-1.0.6.tar.gz cd xnee-1.0.6 ./configure make make install
RPM 软件包可在主页上找到,Xnee 也可在 FreeBSD ports tree 中找到。Xnee 附带各种格式的用户手册和开发者手册。手册的 TeX 源代码与 Xnee 一起分发,并受 GNU FDL 保护。您可以从 Xnee 主页下载您选择的格式(PDF、HTML、INFO 和 TXT),而无需自己构建文档。截至撰写本文时,Xnee 文档版本为 1.0.4。解压文档
tar zxvf xnee-doc-1.0.4.tar.gz
运行 Xnee 时,请确保已启用 RECORD 扩展。在 XFree86 上,请确保已加载 RECORD 模块。打开 XFree86 配置文件,通常为 /etc/X11/XF86Config-4,并在 Module 部分中查找。应包含以下行
Load "record"
在本节中,我们不深入探讨 Xnee 的任何细节,而是从一个简单的示例开始慢慢介绍。使用 --all-events 选项启动 Xnee。这将设置记录一些事件。在进行认真的 Xnee 操作时,此选项没有用。它旨在简化您对 Xnee 的使用介绍
xnee --all-events
当移动鼠标或按下按钮或按键时,Xnee 会打印有关操作的信息。我们继续记录一个简单的会话,然后立即重放它。要记录 20 次鼠标移动,请像这样启动 Xnee
xnee --record --out session1.xnr \ --device-event-range MotionNotify --loops 20
命令行上的选项意味着使用记录模式 (--record),将输出保存在名为 session1.xnr 的文件中 (--out session1.xnr),记录设备事件 MotionNotify (--device-event-range MotionNotify) 并记录 20 个事件 (--loops 20)。
要重放此事件,请像这样启动 Xnee
xnee --replay --file session1.xnr
Xnee 使用范围来解释要记录的内容。范围具有起始值和停止值。可以记录以下数据:核心请求、设备事件、传递事件、错误、回复、扩展请求和扩展回复。我们在本文中不描述上述数据。如果您想了解更多信息,请参阅 RECORD 扩展文档。例如,当您要记录设备事件 MotionNotify 时,请使用
--device-event-range MotionNotify
要记录从 KeyPress 到 MotionNotify 和 CreateNotify 的事件,请使用
--device-event-range KeyPress-MotionNotify,\ CreateNotify
如果您想要更短的命令行,可以使用与事件名称对应的数字而不是名称本身。要查找要记录的数据的编号,请使用 Xnee 的 --print-data-name 选项
xnee --print-data-name
您可以通过设置要记录的数据的数量(--loops 选项)来停止记录,也可以通过发送 TERM 信号(在启动 Xnee 的终端窗口中按 Ctrl-C)来中断 Xnee。或者,您可以指定一个修饰符和按键组合,在记录期间不会用于执行任何其他操作。修饰符和按键的设置是通过 --stop-key 选项完成的。要设置 Xnee,以便在按下 Ctrl-Alt-A 时停止记录,请将以下内容添加到命令行选项
--stop-key Control+Alt,a
但是,当您无法重放除设备事件之外的其他数据时,为什么要费心记录这些数据呢?Xnee 使用其他数据进行同步,这才是事情变得复杂的地方。想想在使用 Galeon 或任何其他 Web 浏览器时记录会话。记录时,一切顺利,网络已启动并正在运行。但是,当重放 Galeon 会话时,您无法访问互联网。如果没有同步,Xnee 可能会重放用户事件,例如单击网页上的链接。如果 Galeon 无法加载页面,则在网络启动并且可以加载页面之前继续重放是没有用的。
当记录其他数据时,我们可以使用它来同步会话。例如,如果我们记录在 Galeon 窗口中显示网页时发送的数据,我们可以等待在重放时发送相同的数据。这确保了网页在我们继续并重放即将到来的事件之前加载。在此示例中,我们跳过了在记录时发送的大量 X 协议数据,以使其保持简单(参见表 1)。当重放这个简单的会话时,Xnee 使用相同的事件(参见表 2)。
表 1. Galeon 测试开始时的 X 事件
协议数据名称 | 用户或客户端操作 |
---|---|
MotionNotify | 用户将指针移动到 Galeon 启动图标。 |
ButtonPress | 用户按下按钮,Galeon 启动。 |
CreateNotify | Galeon 已启动,窗口已创建。 |
VisibilityNotify | 启动页已加载并对用户可见。 |
MotionNotify | 用户将指针移动到加载页面上的链接。 |
ButtonPress | 用户单击链接。 |
VisibilityNotify | 新页面已加载并对用户可见。 |
表 2. Xnee 如何重放测试会话
协议数据名称 | Xnee 操作 |
---|---|
MotionNotify | Xnee 将指针移动到 Galeon 启动图标。 |
ButtonPress | Xnee 按下按钮,Galeon 启动。 |
CreateNotify | Xnee 等待发送此事件。当 Xnee 收到 CreateNotify 通知时,它将继续处理文件中的下一个事件。 |
VisibilityNotify | Xnee 等待发送此事件。由于网络已断开,并且无法加载页面,因此不会发送此事件。Xnee 继续等待。最终,事件被发送,Xnee 可以继续。 |
MotionNotify | Xnee 将指针移动到加载页面上的链接。 |
ButtonPress | Xnee 单击此链接。 |
VisibilityNotify | 新页面已加载并可见。 |
虽然需要同步,但找到用于同步的正确数据可能很困难。Xnee 通过插件文件解决了这个问题,这些插件文件指定了应为一系列应用程序记录的内容。这些插件以它们旨在测试的应用程序命名。如果您想测试您编写的浏览器,使用 Galeon 插件将是一个好主意。但是,有时没有插件适合您的程序,您需要找到正确的协议数据来进行同步。以下示例有望使您将来更容易。我们选择 gnumeric 作为需要找到正确选项的程序。首先,启动 gnumeric。然后在终端模拟器中使用以下选项启动 Xnee
xnee --delivered-event-range \ EnterNotify-MappingNotify --human-printout \ --loops 1000
这将生成大量无用的事件,这些事件会填满屏幕,因此请停止 Xnee。通过在设置范围时排除这些无用事件来过滤掉它们
xnee --delivered-event-range \ EnterNotify-KeymapNotify,VisibilityNotify- \ MappingNotify --human-printout --loops -1
这看起来好多了。现在,使用以下选项开始使用 Xnee 记录会话
@cx:xnee --delivered-event-range \ EnterNotify-KeymapNotify, \ VisibilityNotify-CirculateRequest, \ SelectionClear-MappingNotify --loops \ 1000 --out session1.xnr
在 gnumeric 电子表格中键入一些内容,并使用菜单插入今天的日期或其他输入。完成后,转到终端并按 Ctrl-C 停止记录。现在是重放会话的时候了。将 gnumeric 设置为记录时的状态。像这样在重放模式下启动 Xnee
xnee --replay -f session1.xnr
Xnee 有时会在重放会话时暂停。如果协议数据的发送顺序与记录顺序不同,则会发生这种情况。Xnee 暂停执行一段时间,以便等待服务器发送预期的数据(从文件中读取)。最终,超时到期,Xnee 尝试继续。如果 Xnee 无法在记录的数据流量和重放时发送的数据流量之间同步,它将退出。
Xnee 支持通过插件提供记录选项。当您找到应用程序的设置时,请将它们保存在插件文件中。插件文件的语法类似于命令行选项。创建新插件的最简单方法是复制旧插件,填写您的设置,然后将其重命名为适当的名称。Xnee 随附了用于不同客户端的插件。如果您想为您的应用程序发送插件文件给 Xnee,请这样做。Xnee 主页上有关于如何贡献的说明。
如果您的程序创建窗口以进行用户反馈,则必须确保这些窗口弹出在相同的位置。Xnee 记录所有设备事件,其坐标引用根窗口,而不是创建的窗口。
为了简化记录,请制作脚本,以使用特定用途的正确设置启动 Xnee。您可以将启动器添加到面板,或将菜单项添加到窗口管理器菜单。
Henrik Sandklef 与他的妻子和女儿住在哥德堡(瑞典)。他大部分清醒的时间都与家人在一起,做饭、破解和评估 GNU 软件,偶尔也会尝试踢足球。您可以通过 hesa@gnu.org 与他联系。