软件测试中GUI回归测试
尽管GUIs(Graphical User Interfaces)包含了目前已开发出的很多软件的很大一部分,并可以通过快速原型建立,但目前没有有效的GUI回归测试技术。对于GUI回归测试的需求不同于对传统软件回归测试的需求。当GUI的结构被修改时,原始结构GUI的测试用例在新结构上要么不可重用要么作废。因为GUI测试用例的升级代价是很昂贵的,我们的目的就是使那些不可重用的测试用例可用。使不可用的用例可用化从没被研究过。
本文中,我们将说明对于GUI而言,大量测试用例的不可用是一个严重的问题。我们将展示一个崭新GUI回归测试技术,首先在GUI结构发生变化时自动判断测试用例是否仍然可用。而后判断那些不可用的测试用例中哪些是可以被修复的并应用到修改后的GUI。最后修复这些可修复的测试用例。我们的技术整合到GUI测试框架中,对于任意一个测试用例,都将自动在GUI执行。我们将通过两个测试案例说明我们的技术是有效的,可以使很多测试用例修复,时间执行效率也是可以接受的。
1 介绍
GUI在当今的软件系统中非常普及,占据了软件代码的半壁江山。一个软件系统的GUI的正确性对于确保整个软件系统的顺利运行至关重要。一个普遍的方法是通过对GUI进行测试来确定GUI的正确性。GUI测试要求测试用例(一系列激活GUI窗口的GUI事件)在GUI中产生并执行。然后,目前对于获取GUI测试用例的可行技术是基于资源,需要大量的人工干预。尽管目前有少量的有关自动产生GUI测试用例的文献资料,但在实际操作中,测试用例仍然是通过手工的使用[抓取/重放]工具得到的。
当使用[抓取/重放]工具时,测试人员需要与被测应用程序(AUT,application under test)有所互动;[抓取]可以在文件中保存这些互动,以便[重放]工具可以将它们重放。经验证明,通过使用[抓取/重放]工具,为50个来自不同的窗口的事件生成一个测试用例打工需要20-30分钟。因为需要花费时间,测试人员对于软件界面只生成较少(100-300)的测试用例,因此每一个测试用例都是很珍贵的。
另外,大多数的GUI都是使用快速原型法设计的,这样软件可以在层叠式地进行更新和测试。GUI结构不断的修改要求测试用例可以在不同版本的软件上都是可用的。因为为不同版本的软件生成新的测试用例是非常昂贵的。
尽管回归测试对于传统软件而言是一项非常重要的软件维护手段,占据了大约1/3的软件开发成本,对于GUI的回归测试仍然是一个巨大的有待开发的领域。对于GUI回归测试的需求不同于传统软件对于回归测试的需求。回归测试的研究过去都集中于发展回归测试中的选择技术,这项技术的作用就是从一系列测试用例中选择一部分,这部分用例表明了正确的输入并认为对于验证修改后的软件是必不可少的。那些不能够在新的软件上使用的测试用例将被忽略并丢弃。不可用用例问题对于GUI而言更为严重,因为GUI结构的改变将导致大量测试用例不可用,需要昂贵的更新成本。
当GUI发生变化时,一个测试集合中的测试用例就可被归纳为两类:可用以及不可用。在可用的范畴中,这些测试用例还是可以在修改后的GUI上使用。而在不可用范畴内的测试用例是不能再重用的。例如,一个测试用例里可能包含点击按钮的操作,但这个按钮很可能在新的结构中被删除或是转移到其他地方了。早期的[抓取/重放]工具是根据GUI窗口的对应像素来表示用户事件的。然而,目前的[抓取/重放]工具不再只依赖于坐标,而且还包含了额外的信息如句柄、类型以及(可能的话)窗体的标签,使得当控件被移走时[重放]工具仍然可以定位到正确的窗口。然而即便是用了这些现代的工具,由于GUI结构的修改,如添加一个新的菜单项,将激活一个对话框的动作从一个菜单换到另一个菜单,或是从一个窗口转移到另一个窗口,因此仍然有大量的测试用例变为不可用。第6部分将说明超过74%测试用例将变为不可用。
本文提出一个崭新的GUI回归测试技术。我们的核心想法是不丢弃那些在修改后的GUI上不可用的测试用例。而是自动地将他们修复以便可以应用到修改后的GUI。我们将注意力集中到产生与原有测试用例有些类似的测试用例上,其原因稍后会加以解释。通过使用这项新的技术,一名测试人员可以(1)重新在修改后的GUI上使用原有的仍然可用的测试用例。(2)修复并试用原先已经不可用的测试用例。(3)产生新的测试用例去测试新的功能。第6部分将说明我们的技术将使超过70%的测试技术被修复。
为了进一步说明GUI的回归测试技术,我们在GUI测试框架中简化了GUI的表示方法。同时我们定义了GUI结构事件的控制模型,使用模型来判断GUI是否改变,判断测试用例是否可用,若不可用是否可以被修复。当有很多种方法可以修复一个测试用例时,所有的方法都将被使用,这样就会生成更多的测试用例。我们已经设计出了自动生成工具、表述工具以及重放已修复测试用例工具。
本文的贡献包括:
1. 首次提出一项回归测试技术,该技术可以从不可用测试用例中自动生成新的测试用例。
2. 测试机将决定测试用例在已修改后的GUI上是可用的还是不可用的,以及不可用的测试用例是否可以被修复。
3. 向修复机输入可修复的测试用例,得到可以在已修改的GUI上使用的测试用例。
4. 实验表明,在现实的应用中,本文提供的方法是有效实用的。
5. 将回归测试技术整合到GUI测试框架中。
在下一部分中,我们将定义一个GUI测试用例,并说明GUI的修改影响GUI测试用例的很多途径。然后,我们将在第3部分定义GUI控制流图和GUI调用图。第4部分中将会介绍一个GUI回归测试的例子。第5部分将详细描述回归测试人员将如何使用本文中的修复技术。在第6部分中,我们将通过在Acrobat Reader和WordPad两个软件上使用回归测试技术说明实验结果。最后,在第7部分中,我们将展示目前的一些相关研究。第8章包括本文的总结和未来的工作。
2 GUI模型和测试案例
在这一部分中,我们首先要介绍在GUI测试框架中GUI的模型。尔后我们将定义一个GUI测试用例并引入不可用以及可用测试模型的定义。
一个GUI被模型化为一组对象或窗口O={o1,o2,…om}(例如,标签、表格、按钮、文本框等)以及一组属性P={p1,p2,…pl}(例如,前景、名称)。每一个GUI都会使用对象的相关属性的某些性质。在任何时刻,GUI的状态都可以通过它所包含的所有对象以及所有属性的值来描述。因此,我们定义GUI的状态为:
定义:GUI的状态是指GUI中包含的所有对象的所有属性的状态集。
GUI的有效初始状态定义如下。
定义:如果GUI在初次被激活时的状态Si∈SI,则状态集SI称作该GUI的有效初始状态。
GUI的状态不是一成不变的,在GUI上运行的事件会改变GUI的状态。这些改变后的状态成为改变态。这些事件将被状态转换器进行定义。
定义:事件E={e1,e2,…,en}是可以使GUI的状态转换到另一个状态的函数。
函数表示Sj = e(Si)用于表示状态Sj是由于执行了事件e由状态Si转换而来的。对于测试人员而言,重要的是符合GUI结构的事件序列。我们将测试中使用到的有效的事件序列定义如下。
定义:GUI的有效事件序列为e1;e2;e3;…;en,其中ei+1将在ei之后立刻执行。
一个事件序列如果不是有效的,将被称作非有效事件序列。例如,在MS Word中,剪切(在编辑菜单下)不能在打开(在文件菜单下)执行后立即被执行,因此事件序列<打开,剪切>就是非有效的(忽略键盘快捷方式)。
最后,还要定义GUI测试用例。
定义:GUI测试用例可以表示为(So,e1;e2;…;en),包括任何S0∈SI,SI为初始状态,e1;e2;…;en为一个有效的事件序列。
如果在测试用例中的初始状态是非有效状态或者它其中的事件是无效的,那么这个测试用例就是不可执行的。
定义:如果GUI的改变造成状态So非有效或是事件序列e1;e2;…;en是无法完成的,则测试用例(So,e1;e2;…;en)是不可用的。
不可用的测试用例是不能在GUI上执行的,通常就会被丢弃。
定义:如果测试用例(So,e1;e2;…;en)是可以在修改后的GUI上执行,则该测试用例是可用的。
因为GUI的测试用例的生成是很昂贵的,因此我们设计了这项新技术来修复不可用的测试用例。首先描述GUI的结构来检测出GUI结构上的变化,然后使用这一信息来修复不可用测试用例。并且,由于目前的GUI都非常的大,例如,它们通常包含大量的事件和窗口,我们的描述将使GUI分割为便于管理的几部分。
3 描述
在本章中,我们将介绍GUI测试框架中将使用到的GUI控制流图(G-CFG)和GUI调用图(G-call graph)。在测试框架中,我们的技术是建立在对全局的描述上的,并可以感知GUI结构的改变。这些图组合在一起可以代表GUI的结构,并可通过遍历GUI事件结构自动获得这些图。
使用G-CFG和一个G-call graph来表示一个GUI,原始的和修改后的描述可以通过比较揭示GUI结构上的改变,并可以辨别不可用测试用例。而且,因为这些描述将GUI的分割为便于管理的部分,修理机可以在同一时刻只专注一个组件。
GUI在本质上是层次化的,层次可以将GUI事件进行分类,这样就可以在GUI的不同部分中独立地分析它们。GUI的一种层次划分,也是在本文涉及到的,是通过测试GUI的对话框窗口获得的。一个对话框窗口一旦被激活,将独占与用户的交互,使用户的焦点落在对话框窗口内,直到该对话框关闭。在Adobe Acrobat软件中的打印对话框就是一个对话框窗口的典型代表。所有其它的GUI窗口都成为非交互窗口,它们仅仅提供了一系列对用户可用的GUI事件,但没有获得用户的焦点。例如,在Adobe Acrobat Reader中,执行了查找事件将打开一个非交互窗口,名称即为查找。
在用户与GUI交互的任何时刻,用户都将在交互对话框的情况下调用事件。这个交互对话框包括一个交互对话框窗口X和一系列被X直接激活或间接激活的非交互对话框窗口。交互对话框将一直存活直到窗口X关闭为止。
定义:GUI成员C是一个有序对(RF, UF),其中RF是用事件来代表一个交互对话框窗口,而UF也是用事件来说明一系列的非交互窗口。每一个UF的元素都是由UF或RF的事件引起的。
由定义可知,一个成员的事件不会中断而去执行其他成员的事件,除非其他成员被特别地激活或是中止。因此,互动窗口的操作非常类似于进程或是方法调用。
GUI成员使用GUI控制流图(G-CFG)进行描述。本质上说,G-CFG描述了与其他事件的所有可能交互关系,类似的,一个控制流图描述了所有可能的程序流程。
图1:Acrobat Reader的部分G-CFG
定义:对于成员C的G-CFG是一个四元组<V, E, B, I>:
1. V是一组点代表成员的所有事件。任意v∈V代表C的一个事件。
2. E∈ V * V是一组相邻点之间的边。如果ej直接在ei后执行,则ej排在ei后面。任意边(Vx, Vy)∈E,表示Vy代表的事件在Vx代表的事件之后。
3. B∈V是一组点,代表的是一些在成员C第一次被激活时对于用户就可用的事件。
4. I∈V是可以激活其他成员的事件集合。
描述Acrobat Reader主要成员的一部分G-CFG如图1所示。在最顶端的是三个点(File, Edit, Help)表示Acrobat Reader中的下拉菜单。它们是在主成员被第一次激活时的可用事件。一旦File在Reader中执行,则Edit、Help、Open和Save中的任何一个都可能被执行。因此在G-CFG中,File和其他这几个点之间都有边连接。从图中看出,Open、About和Discover是虚线椭圆线标识。我们使用这个标识来表示可以激活其他成员的事件,例如,I={Open, About, Discover}。其他事件包括Save、Cut、Copy和Paste。在这些事件中的任何一个执行后,用户可以执行File、Edit或是Help,如图所示。
一旦GUI中的所有成员都独立地被G-CFG表示,下一步就是要建立GUI控制流图来表示成员间的互动关系。这些互动包括激活等操作,定义如下:
定义:如果成员Cx包含可以激活成员Cy的事件ex,则表示Cx激活Cy。
由定义可知,GUI控制流图表示出了GUI中所有成员之间的调用关系。一般来说,成员间的关系可以由直接非循环图(DAG)表示,因为不同的成员都可以激活同一个成员。并且通过拷贝结点,DAG可以转换为树。使用调用树模型上的遍历简化了我们的算法。调用树的定义如下:
定义:一棵GUI调用树是一个三元组<N, R, B>,其中N是GUI的一组成员,而R∈N是可以调用主成员的指派成员。B是一系列直接的边,表示不同成员间的调用关系。例如,如果Cx调用Cy,则(Cx, Cy)∈B。
图2:Acrobat Reader的部分GUI调用树
图2是Acrobat Reader的部分调用树的例子。结点表示GUI的成员,边表示成员间的调用关系。成员的名称说明了他们的功能。例如,FileOpen是Reader中用于打开文件的成员,图2中的树在Main和FileOpen之间有线连接,说明Main包含有一个事件,名称为Open(可参见图1),该事件可以激活FileOpen。
4 GUI回归测试实例
通过(1)GUI结构修改的例子,(2)测试用例对于修改后的GUI不可用的例子,(3)如何分析GUI可以识别不可用用例,(4)不可用用例可以如何修改来获得新的测试用例,我们已经对GUI回归测试技术有了一个整体的认识。如果一个结点的语法发生改变,尽管GUI的输出可能变化但测试用例仍然有可能是可用的。
(a)原始GUI (b)修改后的GUI (c)原始的G-CFG (d)修改后的G-CFG
图3 表示了一个GUI,修改后的版本,以及它们相应的G-CFG图。原始的GUI包含4个事件,Cut、Copy、Paste和Print,当GUI被激活时,这4个动作都可以被访问。修改后的GUI包含4个原始事件中的3个;Print动作被删除而另3个事件被整合到一个下拉菜单里,通过点击Edit可以触发。单个事件的语法都没有改变。图3的(c)和(d)分别展示了原始和修改后的GUI的G-CFG图。原始GUI的G-CFG用4个点代表4个事件。修改后的GUI的G-CFG图与原始GUI的G-CFG图相差很多;它不再是全连结图,Edit动作必须在其他事件执行之前执行。以下4种改变总结了这两张G-CFG的差别:
1. events_deleted = {Print}
2. events_added = {Edit}
3. efg_edges_deleted =
{(Cut,Cut),(Copy,Copy),(Paste,Paste),(Print,Print),(Cut,Copy),(Cut,Paste),(Copy,Cut),(Copy,Paste),
(Copy,Print),(Print,Cut),(Print,Copy),(Print,Paste),(Paste,Cut),(Paste,Copy),(Paste,Print)}
文章来源于领测软件测试网 https://www.ltesting.net/