说明:如下内容是根据2010年我在公司的一次关于UI Automation的Workshop上的PPT整理而来,在公司我和几位同事基于UI Automation开发了一款很是强大的UI自动化测试工具,此工具已经在公司获得普遍运用(有十几个产品采用),用于替代昂贵的、且脚本很难维护的商用软件。此文只探讨UIA相关的一些通用技术和一点点UI自动化测试工具的设计经验,由于保密的须要,涉及到公司的这款测试工具部分此文不作介绍。正则表达式
在没有MSUIA(Microsoft UI Automation,如下简称UIA)以前,你们只能经过MSAA(Microsoft Active Accessibility)、Win32 API等Native的方式来操控Windows控件,要想本身写一个UI自动化测试工具是很难很难的,所以这一领域一直被大厂商所垄断,价格也贵得惊人,不是大的软件公司也是用不起这些工具的(除非盗版),好比QTP、Robot、SilkTest等商用工具。UIA定义了一套全新的、针对UI自动化的接口和模式,以往的Win32和MSAA设计出发点并非为解决UI自动化(Win32旨在提供的通用开发接口,MSAA技术的初衷则是为了方便残疾人使用Windows 程序),而UIA的设计目的(微软也须要一套技术、工具来自动化测试本身的产品)、以及新引入的模式和接口都彻底是针对UI自动化测试的。UIA的出现,让草根UI自动化测试工具成为一种可能,看完本文你如有这样的需求就赶忙本身造一个吧:)架构
在继续介绍UIA以前,你们须要先熟悉UIA的几个名词术语。app
在UIA里,每个UI控件便是一个Automation Element,全部的Elements是存储在一个树状结构中的,Windows的桌面是这颗树的根结点(RootElement)。ide
UIA tree就是上面所指的树,每一个Application均可以看做是一棵子树。工具
Element都有一些属性(Properties),好比Automation ID、Name、ControlType等,要找到一个控件主要是经过这些的属性来查找的。测试
在找到一个控件后,对一个控件进行操控的时候就须要用到这个控件支持的控制模式(Control patterns)了,好比:一个TextBox的ValuePattern能够用来获取TextBox里面的文字。ui
当UI控件有什么变更的时候,可能会触发一些事件(好比:弹出HelpText),若是有Client订阅了这个事件则会收到事件的通知。this
上图左边那部分叫Client,本文指的是UI自动化测试工具,右边叫Application,指的是被测运用程序。Client和Application在启动的时候都会载入UI Automation Core(UIAutomationCore.dll),UI自动化测试工具就是经过UI Automation Core来操控运用程序的。从这个架构图上也能够看到UIA封装了一些MSAA和Win32的接口、屏蔽了Win32和.NET运用程序的差别,UI Automation Core对外提供了统一的接口,这也就大大简化了Client这边的实现。spa
基于UIA这套体系实现UI自动化须要解决的两个核心的问题,一是控件查找(Find Controls);二是控件操做(Control manipulation),下面对此分别进行介绍。设计
UIA除了提供了最基本的遍历整个UIA tree的API(TreeWalker)外,另外也提供了一些Build-in的控件查找API。
TreeWalker是标准的对UIA tree的遍历API,它是一切控件查找API的基础。
UIA自带的这些Build-in的查找API是基于TreeScope和Filting Condition的,查找控件须要定义一个查找范围和过滤条件。
下面是一个最简单的示例,在RootElement桌面下查找子结点里Name属性是“Simple App”的一个控件,由于是在桌面的子结点(一级),它会是一个Application:
Condition winNameCond = new PropertyCondition(AutomationElement.NameProperty, "Simple App"); AutomationElement app = AutomationElement.RootElement.FindFirst(TreeScope.Children, winNameCond)
经过上面的Find Controls找到一个控件后,接下来就是如何操做它实现UI自动化的问题了,好比:点击一个Button,选择一个TreeViewItem等等。下面是一个已作好封装的UITextBox这个控件类里获取TextBox的文字的参考实现:
public virtual string GetText() { object o = new object(); if (this.Element.TryGetCurrentPattern(ValuePattern.Pattern, out o)) { ValuePattern pattern = o as ValuePattern; return pattern.Current.Value; } else { return ""; } }
如上面的代码所示,控件操做有一个固定的模式,首先尝试获取控件的Control Pattern,若是控件存在这样的Control Pattern就经过这个Pattern来操控控件,若是没有则须要自定义这个操做或抛出异常等。
直接基于UIA来实现UI自动化不是不能够,但没有人会这么蛮干。为了获取一个Textbox里的文字这样简单的事情,获得处拷贝上面那段的代码,这是不可取的。因此针对上面说的两个核心的问题,咱们须要在UIA上进行一些简化、封装(固然光有这两点是不够的,好比还须要提供一些Native的支持、UI同步、Log等功能,本文对此不作讨论):
封装经常使用控件的基本操做,如:Button的Click、TreeView的Expand和Collapse、Datagrid的操做等等,使控件的操做变成一个简单的API调用,能够考虑把UIA ControlType里定义的30几种控件中最经常使用的控件基本操做都实现了,这样写测试脚本的时候就很安逸了。一些产品中可能会使用一些非标的控件,对于这些自定义的控件,用标准控件的操控API可能无论用,一般经过下面两种方式来解决这个问题,一是继承标准控件,重写操控API的实现,若是可以实现的话;二是让开发人员改代码,尽可能不要使用非标控件:)
当有了应手的测试工具后,测试脚本的维护依然是个老大难的问题,这个须要有一个好的自动化测试framework来隔离UI的变化,尽可能减小维护成本,一个好的framework大致须要有下面几级的分层:
总之,经过UIA实现一套本身的强大的UI自动化测试工具不是不可能,但愿本文对一些从事UI自动化测试的同窗有所帮助。
原文地址:http://feilong.me/2011/01/ms-ui-automation-tool-design-guide