关于UI Automation框架

摘要:
微软提供的UI自动化框架为Windows平台的自动化测试开发带来了极大的便利。以下是相关代码的摘要。“);10return;11}1213AutomationElementok_button=about_notepad_windows.FindFirst;18ObjectinvokePattern对象;19if20{21.Invoke();22}好吧,以上是面向过程的代码,这不利于重用。让我们把它抽象成一个类。首先,定义一个基类UIAControl,它包含搜索根节点searchRoot、搜索范围searchScope和条件searchConditions。使用这三个对象搜索AutomationElement对象并将其分配给innerElement。默认情况下,AndCondition用于关联所有传入的条件对象,因此将CombineCondition方法设置为虚拟方法,以便如果子类希望使用其他关联条件来处理条件,它可以覆盖:1publicabstractclassUIAControl2{3privateUIAControl searchRoot;4privateTreeScopesearchScope;5privateListsearchConditions;67protectedvoidAddSearchCondition8{9this.searchCondition.Add;10}1112publicUIAControls()13{14searchConditions=newList();15searchScope=TreeScope.Scendant;16}1718publicUIAControll19:this()20{21this.searchRoot=searchRoot2324publicUIAControl25:this()26{27searchConditions.Add;28}2930公共自动化元素。自动化元素信息?

微软提供的UI Automation框架给开发windows平台的自动化测试带来了很大的便利,这里就总结一下相关的代码。

首先,直接使用UI Automation框架,完成一个NotePad的about窗口中的 “OK” button的点击:

 1 AutomationElement root = AutomationElement.RootElement;
 2 AutomationElement about_notepad_windows = root.FindFirst(
 3     TreeScope.Descendants,
 4     new AndCondition(
 5         new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window),
 6         new PropertyCondition(AutomationElement.NameProperty, "About Notepad")));
 7 if (about_notepad_windows == null)
 8 {
 9     Console.WriteLine("About Notepad window doesn't exist!!");
10     return;
11 }
12 
13 AutomationElement ok_button = about_notepad_windows.FindFirst(
14     TreeScope.Children,
15     new AndCondition(
16         new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
17         new PropertyCondition(AutomationElement.NameProperty, "OK")));
18 Object invokePatternObject;
19 if (ok_button.TryGetCurrentPattern(InvokePattern.Pattern, out invokePatternObject))
20 {
21     (invokePatternObject as InvokePattern).Invoke();
22 }

好吧,上面是面向过程的代码,不利于复用,那么让我们来将其抽象成类,

首先定义一个基类UIAControl,它包含有搜索的根节点searchRoot,搜索范围searchScope和条件searchConditions,使用这三个对象来搜索一个AutomationElement对象并将其赋给innerElement,由于默认使用的是AndCondition来关联所有传入的condition对象,所以将CombineCondition方法设为虚方法,以便如果有子类想要使用其他关联条件处理condition的时候可以覆盖:

  1 public abstract class UIAControl
  2 {
  3     private UIAControl searchRoot;
  4     private TreeScope searchScope;
  5     private List<Condition> searchConditions;
  6 
  7     protected void AddSearchCondition(Condition condition)
  8     {
  9         this.searchConditions.Add(condition);
 10     }
 11 
 12     public UIAControl()
 13     {
 14         searchConditions = new List<Condition>();
 15         searchScope = TreeScope.Descendants;
 16     }
 17 
 18     public UIAControl(UIAControl searchRoot)
 19         : this()
 20     {
 21         this.searchRoot = searchRoot;
 22     }
 23 
 24     public UIAControl(IntPtr hwnd)
 25         : this()
 26     {
 27         searchConditions.Add(PropertyConditionFactory.GetHandleCondition(hwnd));
 28     }
 29 
 30     public AutomationElement.AutomationElementInformation? ControlInformation
 31     {
 32         get
 33         {
 34             if (Exists())
 35             {
 36                 return InnerElement.Current;
 37             }
 38             return null;
 39         }
 40     }
 41 
 42     private AutomationElement innerElement;
 43     public AutomationElement InnerElement
 44     {
 45         get
 46         {
 47             if (innerElement == null)
 48             {
 49                 innerElement = SearchElement();
 50             }
 51             return innerElement;
 52         }
 53     }
 54 
 55     protected virtual AutomationElement SearchElement()
 56     {
 57         AutomationElement ele = null;
 58         if (searchRoot == null)
 59         {
 60             ele = AutomationElement.RootElement;
 61         }
 62         else
 63         {
 64             ele = searchRoot.InnerElement;
 65         }
 66 
 67         if (ele == null || 0 == searchConditions.Count)
 68         {
 69             return ele;
 70         }
 71         else
 72         {
 73             Condition conditions = CombineAllConditions();
 74             try
 75             {
 76                 return ele.FindFirst(searchScope, conditions);
 77             }
 78             catch(Exception ex)
 79             {
 80                 Console.WriteLine("Getting exception when searching element: " + ex.Message);
 81                 return null;
 82             }
 83         }
 84     }
 85 
 86     //Can override this method to return other type conditions, default will return AndCondition
 87     protected virtual Condition CombineAllConditions()
 88     {
 89         if (searchConditions.Count > 1)
 90         {
 91             return new AndCondition(searchConditions.ToArray());
 92         }
 93         else if (searchConditions.Count == 1)
 94         {
 95             return searchConditions.First();
 96         }
 97         else
 98         {
 99             return null;
100         }
101 
102     }
103 
104     public virtual bool Exists()
105     {
106         //Before checking existence, set innerElement to null to trigger fresh search.
107         return null != SearchElement();
108     }
109 
110     public bool WaitTillExist(int timeout, int interval = 2000)
111     {
112         Stopwatch stopwatch = new Stopwatch();
113         stopwatch.Start();
114         while (stopwatch.ElapsedMilliseconds < timeout)
115         {
116             if (this.Exists())
117             {
118                 return true;
119             }
120 
121             Thread.Sleep(interval);
122         }
123 
124         return false;
125     }
126 
127     protected bool CallPattern<T>(T pattern, Action<T> action) where T : BasePattern
128     {
129         if (pattern != null)
130         {
131             try
132             {
133                 action(pattern);
134                 return true;
135             }
136             catch (Exception ex)
137             {
138                 Console.WriteLine(ex.Message);
139             }
140         }
141         return false;
142     }
143 
144     protected T GetPattern<T>() where T : BasePattern
145     {
146         var ele = InnerElement;
147         if (ele != null)
148         {
149             try
150             {
151                 var patternIdentifier = (AutomationPattern)(typeof(T).GetField("Pattern").GetValue(null));
152                 return ele.GetCurrentPattern(patternIdentifier) as T;
153             }
154             catch (Exception ex)
155             {
156                 Console.WriteLine(ex.Message);
157             }
158         }
159         return null;
160     }
161 
162     public bool Invoke()
163     {
164         return CallPattern(GetPattern<InvokePattern>(), (pattern) => pattern.Invoke());
165     }
166 }

之后,就可以定义其他控件类型了,下面定义了一个button的对象,只有一个click方法:

 1     public class UIAButton : UIAControl
 2     {
 3         public UIAButton(UIAControl root, string name)
 4             : base(root)
 5         {
 6             AddSearchCondition(PropertyConditionFactory.GetNameCondition(name));
 7             AddSearchCondition(PropertyConditionFactory.GetControlTypeCondition(ControlType.Button));
 8         }
 9 
10         public void Click()
11         {
12             this.Invoke();
13         }
14     }

再定义一个window对象:

 1     public class UIAWindow : UIAControl
 2     {
 3         public UIAWindow(string name)
 4         {
 5             AddSearchCondition(PropertyConditionFactory.GetNameCondition(name));
 6             AddSearchCondition(PropertyConditionFactory.GetControlTypeCondition(ControlType.Window));
 7         }
 8 
 9         public bool Close()
10         {
11             return CallPattern(GetPattern<WindowPattern>(), (pattern) => pattern.Close());
12         }
13 
14         public bool Maximize()
15         {
16             return CallPattern(GetPattern<WindowPattern>(), (pattern) => pattern.SetWindowVisualState(WindowVisualState.Maximized));
17         }
18 
19         public bool Minimize()
20         {
21             return CallPattern(GetPattern<WindowPattern>(), (pattern) => pattern.SetWindowVisualState(WindowVisualState.Minimized));
22         }
23 
24         public bool Resize(int width, int height)
25         {
26             return CallPattern(GetPattern<TransformPattern>(), (pattern) => pattern.Resize(width, height));
27         }
28     }

最后,使用上面两个控件类型来完成Ok按钮的点击:

1 UIAWindow windows = new UIAWindow("About Notepad");
2 UIAButton ok_button = new UIAButton(windows, "OK");
3 if (windows.WaitTillExist(3000))
4 {
5     ok_button.Click();
6 }

当然,如果是稍微上点规模的项目,就需要利用这些控件抽象出一个对应产品功能的produc类了。

如果不想从头写起的话,可以看看开源工具White, 一个优秀的基于UI Automation的测试框架。

免责声明:文章转载自《关于UI Automation框架》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Hadoop对小文件的解决方式基于cesium的GIS洪水淹没三维模拟系统下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

VMP加壳(二):VMP的虚拟化原理

由于CPU只能识别和执行二进制文件,并直接让硬件CPU执行虚拟机的二进制代码,因此只能考虑通过纯软件模拟虚拟机执行代码指令。为了在软件级别模拟CPU执行二进制代码指令,一般的虚拟机指令要么是操作寄存器,虚拟机指令的处理程序必须模拟这些函数。它用于指示虚拟CPU当前执行的代码。为了满足上述要点,2。VMP虚拟机的执行过程(1)考虑启动VT。...

uniapp中组件属性设置不生效的解决方案

例如,每次将滚动视图组件的滚动顶部属性值设置为0时,只能第一次成功返回顶部。组件中滚动顶部的实际值更改后,其绑定属性不会同时更改。...

com.aliyun.openservices.shade.com.alibaba.fastjson.JSONException: exepct '[', but {, pos 1, line 1, column 2

错误报告的原因:您放置了一个非List对象,但希望从packagetest中取出List对象;导入java.text。SimpleDateFormat;导入java.util。阵列列表;导入java.util。日期导入java.util。列表importcom.alibaba.fastjson。JSON;导入com.alibaba.fastj...

TensorRT在ubuntu18.04的安装

安装TensorRT前需要安装Cuda和cudnn,安装步骤可以参考ubuntu安装cuda和cudnn。...

JVM内存状况查看方法和分析工具

Java本身提供了多种丰富的方法和工具,帮助开发人员查看和分析GC和JVM内存的状态。同时,开源社区和商业社区也有一些工具来查看和分析GC和JVM内存的状态。在内存分析中,JVisualVM的最大优点是可以通过安装VisualGC插件来分析GC趋势和内存消耗细节。使用JMap查看当前JVM中每一代的内存状态、JVM中对象的内存使用情况,并导出整个JVM中的内...

Linux下如何确认磁盘是否为SSD

方法1:通过cat/sys/block/sda/queue/rotative查看/sys/block/sda/queet/rotative,返回值0为SSD;返回1表示HDD。方法2:通过lsscsi[root@ssd-testthatsit]#cat/sys/bl...