zoukankan      html  css  js  c++  java
  • 关于UI Automation框架

    微软提供的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的测试框架。

  • 相关阅读:
    一些数学证明
    重头再来
    二次函数传参
    神经网络
    准备写点随笔了
    如何做出响应式的页面 (转)
    自适应,响应式,viewport总结
    edm邮件制作规范
    博客园blog模板整理
    git 常用的命令
  • 原文地址:https://www.cnblogs.com/liupengblog/p/4657762.html
Copyright © 2011-2022 走看看