如何测试 Tk 应用程序

Squish 的 Tk 特定 API 允许您查找和查询对象、访问属性,以及在该应用程序 (AUT) 的解释器中评估任意 Tcl 代码。

此外,Tk 便捷 API 提供以执行常见 GUI 操作的函数,如点击按钮或选择菜单项。

如何测试 Tk 小部件 部分展示了各种示例,说明如何使用脚本 Tk API 访问和测试复杂 Tk 小部件。

Tk 对象名称(限定名称)

Squish 为 Tk 应用程序与其他工具包使用完全不同的对象命名方案。Tk 使用 限定名称 来识别对象,例如 myapp.myframe.mylabel。 Squish 利用 Tk 的现有命名方案并使用它来识别 Tk 测试中的对象。

限定对象名称类似于 myapp.frame1.okbutton。点符号用作分隔符(在文件路径中类似于 /\),用于根据其在对象层次结构中的位置来识别特定的对象。应用程序的主窗口是层次结构的根,包含所有应用程序的顶级小部件,其中一些包含子小部件,以此类推。在上面的示例中,okbuttonframe1 的子代,而 frame1 又是应用程序主窗口 myapp 的子代。

如何查找和查询 Tk 对象

Object waitForObject(objectOrName) 函数返回具有给定限定对象名称的对象的引用。

要查找对象的名称,您可以使用 间谍工具 来访问应用程序。或者,您可以记录一个快速丢弃的测试,在该测试中与所有感兴趣的应用程序对象进行交互,以便将对象名称填充到 对象映射 中。

要获取对象的引用——然后可以查询以检查对象的属性,或者可以用来与对象互动——请使用 Object waitForObject(objectOrName) 函数。例如,在 Tcl 中,您可以使用如下代码:

set button [waitForObject "myapp.frame1.okbutton"]

如果 Object waitForObject(objectOrName) 无法找到指定的对象,或者如果在超时之前对象不可用(例如,如果它处于隐藏状态),则抛出一个脚本错误,该错误会停止脚本的执行。为了检查对象是否存在,并且在找到的情况下才与对象互动,请使用 Boolean object.exists(objectName) 函数。

例如,假设您想要像之前那样找到 okbutton 并点击它,但只想在它存在的情况下这么做。在 Tcl 中,您可以使用以下代码实现这一点:

if {[object exists "myapp.frame1.okbutton"]} {
    set button [waitForObject "myapp.frame1.okbutton"]
    invoke clickButton $button
}

使用限定对象名称与 Object waitForObject(objectOrName) 函数意味着测试工程师可以查询和互动AUT对象层次结构中的所有对象。

如何访问 Tk 对象属性

使用 Tk 脚本 API,可以访问 Tk 几乎所有的小部件属性。

例如,如果您想要更改一个 entry 小部件中的文本,您可以这样做,在适当的限定对象名称和新文本替换适当的地方使用以下 Tcl 代码:

set entry [waitForObject "myapp.frame1.e1"]
property set $entry text "New text"
set text [property get $entry text]
test log [toString $text]

前两行设置新文本;第三行创建一个新变量 text,最后一行将 text 打印到 测试结果 视图中。

如何使用 tcleval

尽管 Squish 测试脚本可以访问 Tk 小部件属性,但这对于测试目的来说仍然不够,因为并非所有您想要查询的信息都可通过这些属性获取。幸运的是,Squish 提供了一个解决方案:函数 String tcleval(code)。此函数可以执行AUT范围内的任意Tcl代码。

注意:此功能仅适用于Tcl/Tk应用程序,而不适用于Perl/Tk。

例如,如果您想检索Tk text小部件的内容,您无法通过小部件属性来做,因为文本无法作为属性获得。您可以代替调用 text 小部件的 get 函数,因为该函数返回给定索引之间的 text 小部件文本。所以要获取全部文本,使用索引 1.0 和 end。下面是如何使用 tcleval 函数来对一个 text 小部件调用 get 的示例:

set text [invoke tcleval ".textfield get 1.0 end"]

完整的 tceval 参数作为一个字符串传递。".textfield" 是 text 小部件的名称(记住在纯Tcl/Tk中,"." 是小部件层次的根)。

如何使用 Tk 便利 API

本节简要介绍 Squish 在 Tk 之上提供的脚本API,以使其轻松执行常见用户操作,例如单击按钮。完整API的详细信息请参阅 Tk 便利 API 部分,该部分包含在 工具参考手册 中。在这里,我们将只展示一些示例,以让用户了解API提供了什么,以及如何使用它。

invoke clickButton [waitForObject \
    ":addressbook\\.tcl.dialog.buttonarea.ok"]
invoke type [waitForObject ":addressbook\\.tcl.dialog.email"] "com"
waitForObjectItem ":addressbook\\.tcl.#menuBar" "File"
invoke activateItem ":addressbook\\.tcl.#menuBar" "File"
waitForObjectItem ":addressbook\\.tcl.#menuBar.#file" "Open..."
invoke activateItem ":addressbook\\.tcl.#menuBar.#file" "Open..."

在这里,我们点击一个按钮,在输入框小部件中输入一些文本,并调用 文件 > 打开 菜单项。这些是最常用的Tk便利函数,虽然API中还有更多。有关在AUT中测试各种Tk小部件的更多示例,请参阅 如何测试 Tk 小部件

如何测试 Tk 小部件

本节说明了如何使用Tcl测试Tk应用程序——特别是测试一些标准Tk小部件。虽然只展示了几个小部件,但相同的原理和实践适用于所有Tk小部件,所以在本节结束时,您应该能够测试AUT中的任何小部件。

实现测试脚本最具挑战性的方面通常是创建测试验证。正如在教程:开始测试 Tk 应用程序插入附加验证点章节中所示,这可以通过使用间谍软件及其点 & 点击界面来完成。但在某些情况下,直接在代码中实现验证点可能更方便——并且更灵活。

要测试和验证代码中的小部件及其属性或内容,首先您需要在测试脚本中访问小部件。要获取小部件的引用,可以使用Object waitForObject(objectOrName)函数。该函数找到给定名称的小部件,并返回其引用。为此,您需要知道您想测试的小部件的名称,您可以使用Spy工具获取名称,并将其添加到对象映射中(以便Squish记住它),然后将对象名称(最好是它的符号名称)复制到剪贴板,以便将其粘贴到我们的测试中。如果您需要收集大量小部件的名称,记录一个模拟测试可能更快、更简单,在手动编写的测试脚本中确保您访问了想要验证的所有小部件。这会使Squish将所有相关名称添加到对象映射中,然后您可以将其复制并粘贴到我们的代码中。

如何测试小部件状态

一个常见的需求是测试小部件的状态,特别是它是否启用或禁用。小部件的state属性包含您想要的信息——以下是一些使用示例

set entry1 [waitForObject ":myapp.entry1"]
test compare [property get $entry1 state] "normal"

set entry2 [waitForObject ":myapp.entry2"]
test compare [property get $entry2 state] "disabled"

此代码验证entry1小部件是启用的,以及entry2小部件是禁用的。

复选框和单选按钮

尽管验证标准Tk单选按钮或复选框是否选中是一个常见需求,但这两个小部件都没有方便的属性可以使用,因此您必须编写比预期的更多代码。

我们将首先验证某个单选按钮是否选中。首先,我们必须检索单选按钮的variablevalue属性,然后我们必须评估这个变量以查看它是否等于值——如果是这样,则单选按钮是选中的。

set radiobutton [waitForObject ":myapp.radiobutton"]
set variable [property get $radiobutton "variable"]
set value [property get $radiobutton "value"]
set actual_value [invoke tcleval "return \$$variable"]
test compare $actual_value $value

首先,我们必须检索单选按钮的引用,然后我们检索我们感兴趣的这两个属性。接下来,我们使用String tcleval(code)函数评估变量以获取其实际值,最后我们将实际值与属性值进行比较,看看它们是否相同。

对于复选框,我们必须使用类似的方法,除了它们的相关属性是onvalueoffvalue

set checkbutton [waitForObject ":myapp.checkbutton"]
set variable [property get $checkbutton "variable"]
set onvalue [property get $checkbutton "onvalue"]
set actual_value [invoke tcleval "return \$$variable"]
test compare $actual_value $onvalue

在此,我们检索复选框的引用,然后是复选框的variableonvalue属性。就像我们对单选按钮所做的那样,我们评估变量以获取其实际值,并将其与onvalue进行比较,看看它们是否相同。

要验证复选框未被选中,您可以检索offvalue属性并将其与实际值进行比较。如果它们相同,则复选框未选中。

文本字段

可以使用getvalue属性查询标准Tk输入小部件的内容。

set entry [waitForObject ":myapp.entry"]
test compare [property get $entry getvalue] "Houston"

在此,我们检查输入是否包含文本“休斯顿”。

要查询Tk的多行文本小部件的内容,我们调用小部件的get方法,为其提供要检查的文本的开始和结束索引。

set text [invoke tcleval ".textfield get 1.0 end"]
test compare $text "line 1\nline 2"

我们不是检索多行文本小部件的引用,而是使用 String tcleval(code) 函数来执行小部件的 get 方法,传入跨整个内容的索引。这样返回小部件的所有文本。然后我们检查文本是否正好包含两行(文本为“行 1”和“行 2”)。

Squish 不仅限于 Tk 的标准小部件——例如,我们可以测试 BWidget Entry 小部件。

set bentry [waitForObject ":myapp.bentry"]
test compare [property get $entry text] "Apollo"

在这里,我们使用 BWidget 的 text 属性获取其文本,并将其与文本 "Apollo" 进行比较。

列表框

一个常见的要求是检查 Tk 列表框活动的文本项。这可以通过列表框的 get 方法轻松完成。

set active [invoke tcleval ".listbox get active"]
test compare $active "Gemini"

与多行文本小部件类似,我们不是检索列表框的引用,而是使用 String tcleval(code) 函数来执行具有参数 active 的列表框 get 方法,以返回列表框活动项的文本。然后我们像通常一样比较文本,在本例中与文本 "Gemini" 进行比较。

iwidget Radiobox

iwidget Radiobox 与标准 Tk 单选按钮的不同之处在于,它有一个 getvalue 属性,该属性保存当前选中的单选按钮的文本。

set radiobox [waitForObject ":myapp.rbox"]
test compare [property get $radiobox getvalue] "Mercury"

如果有 "Mercury"、"Venus" 和 "Mars" 这样的单选按钮,我们可以通过检索 Radiobox,并将其 getvalue 属性的值与其应该选中的单选按钮的文本进行比较,来验证 "Mercury" 单选按钮是否已选中。

©2024 The Qt Company Ltd. 文档贡献的版权属于各自的所有者。
提供的文档根据由自由软件基金会发布的 GNU 自由文档许可证 1.3 版本 的条款授权。
Qt 和相关标志是芬兰及其在世界其他地区的 The Qt Company Ltd. 的商标。所有其他商标均为各自所有者的财产。