MS UI Automation Introduction

2014-09-17

MS UI Automation是什么

UIA架构

UI自动化模型

UI自动化树概述

UI自动化控件模式概述

UI 自动化属性概述

UI 自动化事件概述

示例

使用UISpy工具

UI自动化提供者

常见问题分析解决

控件无法识别

Timing issue

本地化问题

自动化技术和自动化框架

参考

MS UI Automation是什么[1]


返回

UI Automation 就是用另一个程序来控制UI 程序,模拟用户操作。他包含三步骤:

  1. 找到UI 元素
  2. 模拟用户操作
  3. 检查UI属性和行为

微软UI Automation技术提供了很好的实现模型。简单来讲,它就是几个dll,提供了一套API及其相应的模式,让软件的开发者遵循该模式去实现相应的interface,从而使测试人员更方便的编写UI Automation。

UIA架构[1]


返回

MS UIA明确定义了两个role:UIA Provider即软件本身,也可称为服务器端,UIA Client即自动化脚本和相关的assistive technology applications,见图1。

  • UIA Provider: 开发人员确定控件行为并实现对应的UIA control pattern(注意:对于标准控件而言,默认是支持UIA的,而对于自定义的控件,需要实现该控件的行为对应于UIA所定义的interface。)
  • UIA Client:相对而言,UIA Client则简单了很多,只需调用相关的UIA API去完成自动化测试脚本。

图1 架构简易图

图2 官方架构图

在图2中,Applications是软件本身,也可成为服务器端,Accessibility Tool是客户端,即测试软件或测试工具(如UISpy.exe)。

从图2可得知UIAutomation Core是通信基础代码,而且Applications和Accessibility Tool是通过管道通信的。

UIA主要有4个组件

组件

描述

提供程序 API(UIAutomationProvider.dll 和 UIAutomationTypes.dll)

定义了各种行为的interface,例如,假设有个自定义的控件,开发人员觉得它需要支持Dock行为,就需要实现IDockProvider接口。

客户端 API(UIAutomationClient.dll 和 UIAutomationTypes.dll)

定义了各种控件模式,以及一些用来支持更好的定位控件的辅助条件搜索类

UiAutomationCore.dll

处理提供程序与客户端之间的通信的基础代码(有时也称为 UI 自动化核心)。

UIAutomationClientsideProviders.dll

一组用于标准旧版本控件的 UI 自动化提供程序。(WPF 控件为 UI 自动化提供本机支持。)此支持自动提供给客户端应用程序。

图3 UIA dll 使用

常用命名空间:

namespace

引用的 DLL

读者

System.Windows.Automation

UIAutomationClient;UIAutomationTypes

UI 自动化客户端开发人员;用于查找 AutomationElement 对象、注册 UI 自动化事件以及与 UI 自动化控件模式一起使用。

System.Windows.Automation.Provider

UIAutomationProvider;UIAutomationTypes

除 WPF 之外的框架的 UI 自动化提供程序开发人员。

System.Windows.Automation.Text

UIAutomationClient;UIAutomationTypes

除 WPF 之外的框架的 UI 自动化提供程序开发人员;用于实现 TextPattern 控件模式。

System.Windows.Automation.Peers

PresentationFramework

WPF 的 UI 自动化提供程序开发人员。

UI自动化模型[2]


返回

UI 自动化将 UI 的每一部分作为一个 AutomationElement 向客户端应用程序公开。

元素包含在树结构中,以桌面作为根元素。

AutomationElement 对象公开它们所表示的 UI 元素的通用属性。  其中一个属性是控件类型,它将其基本外观和功能定义为一个可识别的实体:例如按钮或复选框。

此外,元素还公开控件模式,以提供特定于这些元素的控件类型的属性。  控件模式还公开方法,使客户端能够获取有关元素的进一步信息并提供输入。

注意:控件类型和控件模式之间并不是一一对应的关系。  多个控件类型可以支持同一个控件模式,一个控件可以支持多个控件模式,每个控件模式公开其行为的不同方面。 例如,一个组合框至少具有两个控件模式:一个表示其展开和折叠功能,另一个表示选择机制

UI 自动化还通过事件向客户端应用程序提供信息。  与 WinEvent 不同的是,UI 自动化事件并不基于广播机制。 UI 自动化客户端注册特定的事件通知,并且可以请求将特定的 UI 自动化属性和控件模式信息传入其事件处理程序中。 此外,UI 自动化  事件包含到引发该事件的元素的引用。 提供程序可以通过有选择地引发事件来改善性能,具体取决于所有客户端是否在侦听。

UI自动化树概述[3]

在UIA中,程序UI的每一个部分都被认为是一个AutomationElement类,他们是一个树状的结构,Desktop被认为是每个windows based app的UIA树状图的根,从类的定义中,我们也可以看到一个AutomationElement类中有一个static的RootElement属性。

该树的结构中,一共有3中View Model,分别为Raw View, Control View和Content View:

Raw View提供的信息最多,也是其他view的基础,最贴近于程序本身的编程结构;

Control View是Raw View的子集,它最贴近于最终用户所能感知的UI结构,但是它不包含不能和用户相互交互的一些UI,例如listview的header,toolbar等等;

Content View则是Control View的一个子集,它只包含能和用户直接交互真实信息的控件,比如接受键盘输入的Textbox,选择不同值的Combobox;而诸如lable等控件则不会包含在其中。

UI自动化控件模式概述[4]

控件模式需实现定义控件中可用的一项独立功能所需的方法、属性、事件和关系:

  • UI 自动化元素与其父元素、子元素以及同级元素之间的关系描述了 UI 自动化树内元素的结构。
  • UI 自动化客户端使用方法可以操作控件。
  • 属性和事件提供了有关控件模式功能的信息以及有关控件状态的信息。

UIA大概一共定义了38种pattern,代表了常用的控件行为,他们也会提供一些具体的功能性的属性。

  • 对于UIA Provider来说,所做的事情就是定义控件相关的行为,找到该行为对应的模式,并实现该模式;
  • 对于client而言,即访问相关的方法和属性,来实现自动化。

如某个控件需要有InvokePattern,则provider和client相对应的则为:

控件模式类 (Client)

提供程序接口(Provider)

说明

InvokePattern

IInvokeProvider

用于可被调用的控件,如按钮。

UI 自动化属性概述[5]

每个property都由一个数字和名字来标识,provider用数字ID来确定属性请求(出于安全原因,UI 自动化提供程序将从 Uiautomationtypes.dll 中包含的一组单独的类中获取这些对象。);而client则用AutomationProperty类获取具体的某一属性的内容。

UI 自动化事件概述[6]

UIA是采用订阅模型,而不是以前的广播事件模型。定义了四种事件类型:Property change,Element action,Structure change和Global desktop change。

客户端的 UI 自动化事件

示例[8]


返回

下面这个示例用测试程序完成以下操作:

  1. 打开Calculater.exe;
  2. 找到button '3', '+', '5', '-', '2', '=', 并模拟点击它们。这样,计算器屏幕上会显示‘3+5-2’,并计算结果;
  3. 找到计算器屏幕,得到计算结果;
  4. 比较计算结果和预期结果是否一致。一致,则pass;反之,则fail。
 //Reference UIAutomationClient and UIAutomationTypes

 using System;
using System.Windows.Automation;
using System.Windows; namespace CalcClient
{
class CalcAutomationClient
{
AutomationElement calcWindow = null; //Main UI Window element
//The following ID can be obtained from tool: UI Spy
string resultTextAutoID = ""; //ID for Text element of output window
string btn5AutoID = ""; //ID for button 5
string btn3AutoID = ""; // ID for button 3
string btn2AutoID = ""; // ID for button 2
string btnPlusAutoID = ""; // ID for button +
string btnSubAutoID = ""; // ID for button -
string btnEqualAutoID = ""; // ID for button = static void Main(string[] args)
{
CalcAutomationClient autoClient = new CalcAutomationClient(); //Create callback for new Window open event. Test should run only when the main Window shows.
AutomationEventHandler eventHandler = new AutomationEventHandler(autoClient.OnWindowOpenOrClose);
//Attach the event with desktop element and start listening.
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, eventHandler); //Start caculator. When new window opens, the new window open event should fire.
System.Diagnostics.Process.Start("calc.exe"); //Wait execution
Console.ReadLine();
} void OnWindowOpenOrClose(object src, AutomationEventArgs e)
{
if (e.EventId != WindowPattern.WindowOpenedEvent)
{
return;
} AutomationElement sourceElement; try
{
sourceElement = src as AutomationElement; //Check the event source is caculator or not.
//In production code, string should be read from resource to support localization testing.
if (sourceElement.Current.Name == "Calculator")
{
calcWindow = sourceElement;
}
}
catch (ElementNotAvailableException)
{
return;
} //Start testing
ExecuteTest();
} void ExecuteTest()
{
//Execute 3+5-2
//Invoke ExecuteButtonInvoke function to click buttons
ExecuteButtonInvoke(btn3AutoID);
ExecuteButtonInvoke(btnPlusAutoID);
ExecuteButtonInvoke(btn5AutoID);
ExecuteButtonInvoke(btnSubAutoID);
ExecuteButtonInvoke(btn2AutoID);
System.Threading.Thread.Sleep();
ExecuteButtonInvoke(btnEqualAutoID); //Invoke GetCurrentResult function to read caculator output
if (GetCurrentResult() == "")
{
Console.WriteLine("Execute Pass!");
return;
} Console.WriteLine("Execute Fail!");
} void ExecuteButtonInvoke(string automationID)
{ //Create query condition object, there are two conditions.
//1. Check AutomationID
//2. Check Control Type
Condition conditions = new AndCondition(
new PropertyCondition(AutomationElement.AutomationIdProperty, automationID),
new PropertyCondition(AutomationElement.ControlTypeProperty,
ControlType.Button)); AutomationElement btn = calcWindow.FindAll(TreeScope.Descendants, conditions)[]; //Obtain the InvokePattern interface
InvokePattern invokeptn = (InvokePattern)btn.GetCurrentPattern(InvokePattern.Pattern); //Click button by Invoke interface
invokeptn.Invoke();
} string GetCurrentResult()
{ Condition conditions = new AndCondition(
new PropertyCondition(AutomationElement.AutomationIdProperty, resultTextAutoID),
new PropertyCondition(AutomationElement.ControlTypeProperty,
ControlType.Text)); AutomationElement btn = calcWindow.FindAll(TreeScope.Descendants, conditions)[]; //Read name property of Text control. The name property is the output.
return btn.Current.Name;
}
}
}

使用UISpy工具

UISpy可以当作Client,找到Server所提供的属性、控件模式,也可对Server进行模拟操作。

图4 UISpy attached to Calculator

UI自动化提供者

UIA架构中提到:对于标准控件而言,默认是支持UIA的,而对于自定义的控件,需要实现该控件的行为对应于UIA所定义的interface。

这里提到的实现UIA所定义的interface,就是UIA provider。UIA provider可在根据实际情况在服务器端和客户端实现,示例如下:

客户端:

Client-Side UI Automation Provider -  WinForm Sample

服务器端:

Server-Side UI Automation Provider - WinForm Sample

Server-Side UI Automation Provider - WPF Sample

常见问题分析解决[8]


返回

控件无法识别

  1. 如果是因为自动化测试工具的限制,比如对于WinForm的控件,有些自动化工具就不能识别,碰到这种情况,最好是看这个工具有没有扩展可以用,比如Silktest的.Net Framework扩展。如果不行,那只能换自动化测试工具了。所以这个凸显出在做自动化测试以前,选择自动化测试工具的重要性。
  2. 如果是因为控件比较复杂,自动化工具可以识别,但是无法操作。这时我们可以通过Window API以及消息的方式来做,比如自己去调Window API来操作窗口,或者请开发实现一下消息的接口来给自动化工具调用等
  3. 跟开发沟通,让他们的控件支持IAccessible接口,然后我们通过MSAA来操作(如果是WPF控件,则需要实现UIAutomation定义的一些接口)。不过一般情况下,除了微软这样对软件的Accessible要求很高的公司,其它公司很少会花费时间来实现这个接口……。 另外扯一句,产品的Accessible的程度,实质上决定了一个公司能对产品做自动化测试的程度。
  4. 如果以上方法都不行,那只有最后一个双刃剑可以用了,就是鼠标键盘模拟。理论上来说,只要用户可以操作的东西,只要有界面,就可以通过鼠标键盘模拟来实现(君不见N多游戏外挂的键盘鼠标模拟大法)。就如双刃剑一样,这种做法是杀敌一千,自损八百。因为鼠标键盘模拟非常依赖于当前激活的窗口以及光标位置和焦点位置,而且同步起来很困难。这也造成了后期维护成本很高。

Timing issue

提倡第一种方法。

  1. Waiter/EventDriven
  2. Retry sleep a small interval value
  3. Thread.Sleep a long time

本地化问题

Avoid localize issue, read resource string

自动化技术和自动化框架[8]


返回

前面提到了UIA作为全新UI自动化测试技术的优势,但这并不能解决所有的UI 自动化问题。 自动化框架正是为了自动化技术没有完全解决的问题。比如:

  • 自动化中的同步和等待。 对于稍复杂的UI 程序,测试程序往往需要根据测试目标的状态决定 下一步的操作。 比如测试文件另存为功能的时候,若保存路径是网络路径,可能会因为网络延迟导致整个UI停顿比较长的时间。这个时候测试,程序如果不顾当前状态而简单地执行下一步操作,比如新建文件, 很可能会因为UI延迟而失败。 正确的做法是,测试程序应该等待文件保存成功返回后,再进行下一步操作。 这就是自动化中同步和等待的一个例子。实现同步和等待有多种方法,最简单粗暴的做法是硬编码一个长时间的 Sleep在测试代码中。 稍微好一点的做法可以采取小时间片的轮询状态检查, 或者反复重试。 借助 UIA的Event Pattern,可以尝试捕获另存为窗口的关闭WindowClosedEvent。 如果要做得完善一点, 可以把多种方法结合, 另外再额外检查目标程序的CPU使用情况,消息循环是否有回应,设定超时时间等等。
  • 冗繁的编码过程。 对于一个UI窗口,里面可能有几十个子控件或者子窗口。 在编写测试代码的时候, 如果对这些子元素的获取,操作不能简化, 势必导致代码冗繁,难以维护。 借助自动代码生成和ORM (Object Role Modeling)等技术, 可以解决这个问题。 比如可以用工具把窗口及其子元素的关系和搜索条件都序列化到XML文件中, 然后采用ORM技术即可在代码中轻松获取子元素。
  • 多语言和本地化测试。多语言和本地化的测试对UI来说显得尤为重要。 UI程序往往通过资源文件来定义所显示的内容, 这就要求自动化测试要可以方便读取和定位程序的资源文件, 来支持多语言和本地化测试。
  • 支持工具和辅助函数的匮乏。 对于大的项目研发, 通过好的工具来减小开发成本是非常必要的。 就UI自动化来说, 如果自动化测试用例可以通过一次录制,多次播放来做的话,成本会减少很多。 在VS2010中就提供了这样的录制-播放功能。 详细视频可以参考How to create record and playback Test Cases in Visual Studio Beta2。
  • 区分功能性测试和用户真实行为模拟。 前面提到, 就点击按钮功能来说, 可以通过SendKey来模拟鼠标操作, 或者通过Windows Message来直接触发点击事件。 这两种不同方法各有优劣。 比如当按钮被其它元素遮挡, 通过SendKey进行模拟就会导致失败,而直接发送Windows Message还是会成功。 孰优孰劣取决于要达到的目的。 如果单纯为了测试按钮点击后导致的结果,通过Windows Message来模拟就省去了很多麻烦。 相反, 如果是界面测试, 通过SendKey来模拟就可以让按钮被遮挡的bug暴露出来, 而Windows Message则不能发现这样的问题。

所以,单纯的某个自动化技术或者方法也无法满足需求。为了解决上述问题,各种自动化测试框架逐渐涌现和发展。微软内部有多个不同的自动化框架,设计理念和侧重点各有不同。 Visual Studio 2010将加入对自动化测试的支持。 在CodePlex上面, 也可以找到多种框架,比如White和UI Automation Verify。

参考

[1] MS UI Automation简介

[2] UI 自动化概述

[3] UI 自动化树概述

[4] UI 自动化控件模式概述

[5] UI 自动化属性概述

[6] UI 自动化事件概述

[7] 使用 UI 自动化进行自动化测试

[8] UI Automation - under the hood

MS UI Automation Introduction的更多相关文章

  1. MS UI Automation简介

    转自:http://blog.csdn.net/ffeiffei/article/details/6637418 MS UI Automation(Microsoft User Interface A ...

  2. UI Automation 简介

    转载,源地址: http://blog.csdn.net/ffeiffei/article/details/6637418 MS UI Automation(Microsoft User Interf ...

  3. 使用UI Automation实现自动化测试--1

    Introduction UI Automation是Microsoft .NET 3.0框架下提供的一种用于自动化测试的技术,是在MSAA基础上建立的,MSAA就是Microsoft Active ...

  4. 使用UI Automation实现自动化测试--1-4

    Introduction UI Automation是Microsoft .NET 3.0框架下提供的一种用于自动化测试的技术,是在MSAA基础上建立的,MSAA就是Microsoft Active ...

  5. 使用UI Automation实现自动化测试--5-7

    使用UI Automation实现自动化测试--5 (Winfrom和WPF中弹出和关闭对话框的不同处理方式) 在使用UI Automation对Winform和WPF的程序测试中发现有一些不同的地方 ...

  6. UI Automation Test

    UI Automation test is based on the windows API. U can find the UI Automation MSDN file from http://m ...

  7. 使用UI Automation实现自动化测试 --工具使用

    当前项目进行三个多月了,好久也没有写日志了:空下点时间,补写下N久没写的日志 介绍下两个工具 我本人正常使用的UISpy.exe工具和inspect.exe工具 这是UISPY工具使用的图,正常使用到 ...

  8. Server-Side UI Automation Provider - WPF Sample

    Server-Side UI Automation Provider - WPF Sample 2014-09-14 引用程序集 自动化对等类 WPF Sample 参考 引用程序集 返回 UIAut ...

  9. Client-Side UI Automation Provider - WinForm Sample

    Client-Side UI Automation Provider -  WinForm Sample 2014-09-15 源代码 目录 引用程序集实现提供程序接口分发客户端提供程序注册和配置客户 ...

随机推荐

  1. Matlab实现网络拓补图

    顶点号 顶点号 权值 1 2 400 1 3 450 2 4 300 2 8 230 2 9 140 3 4 600 4 5 210 4 19 310 5 6 230 5 7 200 6 7 320 ...

  2. [工作积累] 32bit to 64bit: array index underflow

    先贴一段C++标准(ISO/IEC 14882:2003): 5.2.1 Subscripting: 1 A postfix expression followed by an expression ...

  3. Unity3D判断鼠标向右或向左滑动,响应不同的事件

    private var first = Vector2.zero; private var second = Vector2.zero; function Update () { } function ...

  4. 【译】C++工程师需要掌握的10个C++11特性

    原文标题:Ten C++11 Features Every C++ Developer Should Use 原文作者:Marius Bancila 原文地址:codeproject 备注:非直译,带 ...

  5. 简单的说说jsonp

    jsonp和json有什么区别?json是一种文件格式,而jsonp是一种技术方法. jsonp会被人认为是一种新的跨域技术,其实本质上和利用带有src属性的标签进行js跨域本质没什么区别. 区别就是 ...

  6. appium获取android app的包名和主Activity

    方法一在appium的android setting中选择下载到电脑上的app包,获取Activity. 方法二在android-sdk中安装build-tools包,进入这个目录.aapt dump ...

  7. POJ 2142 The Balance (解不定方程,找最小值)

    这题实际解不定方程:ax+by=c只不过题目要求我们解出的x和y 满足|x|+|y|最小,当|x|+|y|相同时,满足|ax|+|by|最小.首先用扩展欧几里德,很容易得出x和y的解.一开始不妨令a& ...

  8. light oj 1205 - Palindromic Numbers 数位DP

    思路:搜索的时候是从高位到低位,所以一旦遇到非0数字,也就确定了数的长度,这样就知道回文串的中心点. 代码如下: #include<iostream> #include<cstdio ...

  9. Good Bye 2015 A. New Year and Days 签到

    A. New Year and Days   Today is Wednesday, the third day of the week. What's more interesting is tha ...

  10. C#反射Assembly 详细说明

    1.对C#反射机制的理解2.概念理解后,必须找到方法去完成,给出管理的主要语法3.最终给出实用的例子,反射出来dll中的方法 反射是一个程序集发现及运行的过程,通过反射可以得到*.exe或*.dll等 ...