zoukankan      html  css  js  c++  java
  • 微软平台UI自动化(UIA)经验集

    根据我UIA自动化测试的经验, 总结了下面代码集. 在这个代码集中, 包含了:

    1. 一个WPF的窗体程序

    2. 一个WinForm的窗体, 这个窗体作为Model Dialog被WPF主程序打开

    3. 针对这个WPF和WinForm的测试代码例子

    4. 针对Win7 Calc.exe的测试代码例子

    5. 一个简单的TestEngine

    这个代码集的作用是:

    1. 演示UIA中基本的概念, 比如AutomationID, AutomatonName, InvokePattern等的调用

    2. 演示如何处理UI自动化的timing issue.

    3. 演示简单WaitForReady的实现方法

    4. 演示Click和Invoke的差别

    5. 演示一个简单的UIA Engine

    6. 演示如何通过AutomationPeer来给自绘画图案实现Invoke Pattern

    7. 演示如何对WinForm实现Server side provider

    8. 演示如何对WPF的databinding item设定AutomationID

    WPF主窗口代码:

    代码
    public partial class Window1 : Window
        {
            
    private StackPanel pane;
            
    private TextBlock timeBlock;
            
    private Button buttonOpenNewWindow;
            
    private ListBox listboxStringBinding;
            
    private ListBox listboxManual;
            
    private SelfDrawControl selfControl;
            
    private DispatcherTimer tmr=new DispatcherTimer();
            
    private DispatcherTimer deplyedExecution=new DispatcherTimer();
            
    private Button kickoffFlashWindow;
            
    private Button startWinformHoster;
            
    private Button buttonNoAutomationID;
            
    private Button busyButton;

            
    private int busyCount = 0;

            
    public Window1()
            {
                InitializeComponent();
                
    this.Name = "Window1";
                CreateControls();
                
            }

            
    void CreateControls()
            {
                pane 
    = new StackPanel();
                pane.Name 
    = "StackPane";
                
    this.Content = pane;

                timeBlock 
    = new TextBlock();
                timeBlock.Name 
    = "TimeBlock";
                pane.Children.Add(timeBlock);

                buttonOpenNewWindow 
    = new Button();
                buttonOpenNewWindow.Name 
    = "ButtonOpenNewWindow";
                buttonOpenNewWindow.Content 
    = "Open New Window";
                pane.Children.Add(buttonOpenNewWindow);

                
    //直接binding的Listbox子元素没有AutomationID
                listboxStringBinding = new ListBox();
                listboxStringBinding.Name 
    = "ListBox_Item_WithoutAutomationID";
                listboxStringBinding.DataContext 
    = new string[] { "1""2""3" };
                Binding bind 
    = new Binding();
                bind.Source 
    = new string[] { "1""2""3" };             
                listboxStringBinding.SetBinding(ListBox.ItemsSourceProperty, bind);
                pane.Children.Add(listboxStringBinding);
               

                selfControl 
    = new SelfDrawControl();
                selfControl.Name 
    = "SelfDrawControl";
                pane.Children.Add(selfControl);

                listboxManual 
    = new ListBox();
                listboxManual.Name 
    = "ListBox_Item_ManualBindAutomationID";
                
    for(int i=0;i<5;i++)
                {
                    
    //手动添加的的Listbox子元素可以通过下面的方法指定AutomationID,或者直接指定Name
                    ListBoxItem item=new ListBoxItem();
                    item.SetValue(System.Windows.Automation.AutomationProperties.AutomationIdProperty, 
    "ManualItem" + i.ToString());
                    item.Content 
    =i;
                    listboxManual.Items.Add(item);
                }
                pane.Children.Add(listboxManual);

                kickoffFlashWindow 
    = new Button();
                kickoffFlashWindow.Name 
    = "ButtonOpenFlashWindow";
                kickoffFlashWindow.Content 
    = "Kick off Flash Window";
                pane.Children.Add(kickoffFlashWindow);
                kickoffFlashWindow.Click 
    += new RoutedEventHandler(kickoffFlashWindow_Click);

                startWinformHoster 
    = new Button();
                startWinformHoster.Name 
    = "ButtonOpenWinForm";
                startWinformHoster.Content 
    = "Start Winform Hoster";
                pane.Children.Add(startWinformHoster);
                
    //startWinformHoster.Click += delegate{(new WinFormControlHoster()).ShowDialog();};
                startWinformHoster.Click += new RoutedEventHandler(startWinformHoster_Click);

                tmr.Interval 
    = new TimeSpan(0,0,0,0,500);
                tmr.Tick 
    += delegate { this.timeBlock.Text = DateTime.Now.ToString("U"); };
                tmr.IsEnabled 
    = true;
                buttonOpenNewWindow.Click 
    += new RoutedEventHandler(buttonOpenNewWindow_Click);

                buttonNoAutomationID 
    = new Button();
                buttonNoAutomationID.Content 
    = "Button Wihtout AutomationID";
                pane.Children.Add(buttonNoAutomationID);

                busyButton 
    = new Button();
                busyButton.Name 
    = "BusyButton";
                busyButton.Content 
    = busyCount.ToString();
                pane.Children.Add(busyButton);
                busyButton.Click 
    += new RoutedEventHandler(busyButton_Click);

                deplyedExecution.Interval 
    = new TimeSpan(005);
                deplyedExecution.Tick 
    += new EventHandler(deplyedExecution_Tick);
                deplyedExecution.IsEnabled 
    = false;
            }

            
    void busyButton_Click(object sender, RoutedEventArgs e)
            {
                busyCount
    ++;
                busyButton.Content 
    = busyCount.ToString();
                
    for (int i = 1; i < 10; i++)
                {
                    System.Threading.Thread.Sleep(
    150);
                }
            }

            
    void buttonOpenNewWindow_Click(object sender, RoutedEventArgs e)
            {
                BindingWithAutomationID bwid 
    = new BindingWithAutomationID();
                bwid.ShowDialog();
            }

            
    void kickoffFlashWindow_Click(object sender, RoutedEventArgs e)
            { 
                deplyedExecution.IsEnabled 
    = true;
            }

            
    void deplyedExecution_Tick(object sender, EventArgs e)
            {
                FlashWindow fw 
    = new FlashWindow(new TimeSpan(0,0,3));           
                fw.Show();
                deplyedExecution.IsEnabled 
    = false;            
            }

            
    void startWinformHoster_Click(object sender, RoutedEventArgs e)
            {
                System.Windows.Forms.Form fm 
    = new MyForm();
                fm.ShowDialog();
            } 
        }

    WPF自绘窗口的代码, 以及对应AutomationPeer的实现:

    代码
    public partial class SelfDrawControl : UserControl
        {
            
    public SelfDrawControl()
            {
                InitializeComponent();
            }

            
    protected override void OnRender(DrawingContext dc)
            {
                dc.DrawRectangle(Brushes.Blue, 
    new Pen(Brushes.Blue, 10), new Rect(new Point(00), new Point(RenderSize.Width / 2, RenderSize.Height)));
                dc.DrawRectangle(Brushes.Black, 
    new Pen(Brushes.Black, 10), new Rect(new Point(RenderSize.Width / 20), new Point(RenderSize.Width, RenderSize.Height)));
            
            }

            
    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
            {
                Point point 
    = e.GetPosition(this);
                
    if (point.X > 0 && point.X < RenderSize.Width / 2)
                {
                    DoClick(
    "blue");
                }
                
    else
                {
                    DoClick(
    "black");
                }
                
    base.OnMouseLeftButtonDown(e);
            }

            
    internal void DoClick(string color)
            {
                MessageBox.Show(color);
            }

            
    protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
            {
                var peer 
    = new SelfDrawControlAutomationPeer(this);
                peer.InvalidatePeer();
                
    return peer;
            }       
        }

        
    public class SelfDrawControlAutomationPeer :UserControlAutomationPeer
        {
            SelfDrawControl target;
            List
    <AutomationPeer> children = null;
            
    public SelfDrawControlAutomationPeer(SelfDrawControl target):base(target)
            {
                
    this.target = target;
            }

            
    protected override AutomationControlType GetAutomationControlTypeCore()
            {
                
    return AutomationControlType.Window;
            }

            
    protected override string GetClassNameCore()
            {
                
    return target.GetType().ToString();
            }

            
    /*
             * 特别注意, 生成ChildrenCore的时候务必维护父子关系
             * UI Testclient 可能在不同child parent之间遍历
             * 务必保证childpeer.Parent = parent.Children[n]
             * 否则会带来各种意外,这是在实现自定义Peer时候的最大陷阱
            
    */ 

            
    protected override List<AutomationPeer> GetChildrenCore()
            {
                
    //return null;

                
    if (children == null)
                {
                    children 
    = new List<AutomationPeer>();
                    SelfDrawControlElementAutomationPeer bluepeer 
    = new SelfDrawControlElementAutomationPeer(target, this"blue");
                    SelfDrawControlElementAutomationPeer redpeer 
    = new SelfDrawControlElementAutomationPeer(target, this"red");
                    children.Add(bluepeer);
                    children.Add(redpeer);
                }

                
    return children;
            }

        }

        
    public class SelfDrawControlElementAutomationPeer : AutomationPeer, IInvokeProvider, IValueProvider
        {
            
    private string color;
            SelfDrawControl target;
            SelfDrawControlAutomationPeer parentPeer;

            
    public SelfDrawControlElementAutomationPeer(SelfDrawControl target, SelfDrawControlAutomationPeer parentPeer, string color)             
            {
                
    this.color = color;
                
    this.target = target;
                
    this.parentPeer = parentPeer;

                var o
    =this.GetParent();
            }

            
    public void Invoke()
            {
                target.DoClick(color);
            }

            
    public bool IsReadOnly { get { return true; } }
            
    public string Value { get { return color; } }
            
    public void SetValue(string value) { }

            
    protected override string GetAcceleratorKeyCore()
            {
                
    return string.Empty;
            }
           
       
            
    protected override string GetAccessKeyCore()
            {
                
    return string.Empty;
            }
          
            
    protected override AutomationControlType GetAutomationControlTypeCore()
            {
                
    return AutomationControlType.Window;
            }
          
            
    protected override string GetAutomationIdCore()
            {           
                
    return target.Name+"-"+color;
            }
        
            
    protected override Rect GetBoundingRectangleCore()
            {

                Rect parentRect
    =parentPeer.GetBoundingRectangle();

                
    if(color=="blue")
                {
                    
    return new Rect(new Point(parentRect.X, parentRect.Y), new Point(parentRect.X + target.RenderSize.Width / 2, parentRect.Y+target.RenderSize.Height));
                }
                
    if(color=="red")
                {
                    
    return new Rect(new Point(parentRect.X + target.RenderSize.Width / 2, parentRect.Y), new Point(parentRect.X + target.RenderSize.Width, parentRect.Y + target.RenderSize.Height));
                }
                
    return Rect.Empty;
            }
         
            
    protected override List<AutomationPeer> GetChildrenCore()
            {
                
    return null;
            }
       
            
    protected override string GetClassNameCore()
            {
                
    return "SelfDrawControlInnerGraphic";
            }
          
            
    protected override Point GetClickablePointCore()
            {
                
    return new Point(0,0);
            }
      
            
    protected override string GetHelpTextCore()
            {
                
    return "This is my HelpText";
            }
          
            
    protected override string GetItemStatusCore()
            {
                
    return "Status is active";
            }
        
            
    protected override string GetItemTypeCore()
            {
                
    return "This is my item type";
            }
         
            
    protected override AutomationPeer GetLabeledByCore()
            {
                
    return this;
            }
          
            
    protected override string GetNameCore()
            {
                
    return "Name is :"+color;
            }
           
            
    protected override AutomationOrientation GetOrientationCore()
            {
                
    return AutomationOrientation.None;
            }
         
            
    public override object GetPattern(PatternInterface patternInterface)
            {
                
    if(patternInterface== PatternInterface.Invoke || patternInterface== PatternInterface.Value)
                {
                    
    return this;
                }
                
    return null;
            }
         
            
    protected override bool HasKeyboardFocusCore()
            {
                
    return false;
            }
           
            
    protected override bool IsContentElementCore()
            {
                
    return true;
            }
         
            
    protected override bool IsControlElementCore()
            {
                
    return true;
            }
      
            
    protected override bool IsEnabledCore()
            {
                
    return true;
            }

            
    protected override bool IsKeyboardFocusableCore()
            {
                
    return false;
            }
       
            
    protected override bool IsOffscreenCore()
            {
                
    return false;
            }
          
            
    protected override bool IsPasswordCore()
            {
                
    return false;
            }
        
            
    protected override bool IsRequiredForFormCore()
            {
                
    return false;
            }
           
            
    protected override void SetFocusCore()
            {
            }
        }

    BindingWindow的XAML和代码:

    <ListBox Name="InnerListbox" >
            <ListBox.Resources>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="AutomationProperties.AutomationId"  Value="{Binding  RelativeSource={x:Static RelativeSource.Self}, Path=Content}" ></Setter>
                </Style>
            </ListBox.Resources>       
        </ListBox>

    代码
    public partial class BindingWithAutomationID : Window
        {
            
    public BindingWithAutomationID()
            {
                InitializeComponent();
                
    this.Name = "StyleBindingWindow";

                
    //可以使用Style的Setter来给binding的子元素增加AutomationID
                this.InnerListbox.DataContext = new string[] { "1""2""3" };
                Binding bind 
    = new Binding();
                bind.Source 
    = new string[] { "1""2""3" };
                
    this.InnerListbox.SetBinding(ListBox.ItemsSourceProperty, bind);            
            }

        }

    WinForm的代码及其Server side provider实现:

    代码
    [ComVisible(true)]
        
    public class MyForm : System.Windows.Forms.Form, IRawElementProviderSimple
        {
            
    private ValuePattern vp = new ValuePattern();
            
    private Timer timer = new Timer();
            
    private string curentNameProperty = string.Empty;

            
    public MyForm()
            {
                timer.Interval 
    = 500;
                timer.Tick 
    += new EventHandler(timer_Tick);
                timer.Enabled 
    = true;

                
    this.Name = "WinFormWindow";
                
    this.Text = "ServerUIAFormDemo";

                Button btn 
    = new Button();
                btn.Text 
    = "This is a WinForm Button";
                btn.Name 
    = "button1";
                
    this.Controls.Add(btn);

                curentNameProperty 
    = string.Format("{0} {1}"this.Name, DateTime.Now.ToLongTimeString());
            }

            
    void timer_Tick(object sender, EventArgs e)
            {
                
    string newNameProperty=string.Format("{0} {1}"this.Name, DateTime.Now.ToLongTimeString());
                AutomationInteropProvider.RaiseAutomationPropertyChangedEvent(
    thisnew AutomationPropertyChangedEventArgs(AutomationElement.NameProperty, curentNameProperty, newNameProperty));
                curentNameProperty 
    = newNameProperty;
            }

            
    protected override void WndProc(ref Message m)
            {

                
    const int WM_GETOBJECT = 0x003D;
                
    if ((m.Msg == WM_GETOBJECT) && (m.LParam.ToInt32() ==
                    AutomationInteropProvider.RootObjectId))
                {

                    m.Result 
    = AutomationInteropProvider.ReturnRawElementProvider(
                            
    this.Handle, m.WParam, m.LParam,
                            (IRawElementProviderSimple)
    this);
                    
    return;

                }
                
    base.WndProc(ref m);
            } 

            
    public Object GetPatternProvider(int patternId)
            {

                
    if (patternId == ValuePatternIdentifiers.Pattern.Id)
                {
                    
    //Create and return ValuePattern object
                    return vp;
                }
                
    else
                {
                    
    return null;
                }
            }

            
    //This function handles all the UIA Property reqeust
            public Object GetPropertyValue(int propertyId)
            {

                
    if (propertyId == AutomationElementIdentifiers.NameProperty.Id)
                {
                    
    return curentNameProperty;
                }

                
    else if (propertyId == AutomationElementIdentifiers.NativeWindowHandleProperty.Id)
                {
                    
    return this.Handle;
                }

                
    else if (propertyId == AutomationElementIdentifiers.AutomationIdProperty.Id)
                {
                    
    return this.Name;
                }

                
    else if (propertyId == AutomationElementIdentifiers.ClassNameProperty.Id)
                {
                    
    return "RootButtonControlClass";
                }

                
    else if (propertyId == AutomationElementIdentifiers.ControlTypeProperty.Id)
                {
                    
    return ControlType.Window.Id;
                }

                
    else if (propertyId == AutomationElementIdentifiers.IsContentElementProperty.Id)
                {
                    
    return false;
                }

                
    else if (propertyId == AutomationElementIdentifiers.IsControlElementProperty.Id)
                {
                    
    return true;
                }
                
    else
                {
                    
    return AutomationElement.NotSupported;
                }

            }

            
    public IRawElementProviderSimple HostRawElementProvider
            {
                
    get
                {
                    
    return AutomationInteropProvider.HostProviderFromHandle(this.Handle);
                }
            }

            
    public ProviderOptions ProviderOptions
            {
                
    get
                {
                    
    //Indicate this is server side implementation
                    return ProviderOptions.ServerSideProvider;
                }
            }
        }

        [ComVisible(
    true)]
        
    public class ValuePattern : IValueProvider
        {
            
    public bool IsReadOnly { get { return true; } }
            
    public string Value
            {
                
    get
                {
                    
    //Return current time as value pattern’s value
                    return DateTime.Now.ToLongTimeString();
                }
            }
            
    public void SetValue(string value) { return; }
        }

    下面是测试程序:

    测试演示1: 演示UIA API里面的cached property:

    代码
    class DemoCachedProperty
        {
            
    public static void Test()
            {
                CacheRequest cacheRequest 
    = new CacheRequest();            
                cacheRequest.TreeScope 
    = TreeScope.Element;
                cacheRequest.Add(AutomationElement.NameProperty);

                
    using (cacheRequest.Activate())
                {
                    AutomationElement wpfRoot 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "Window1"));
                    AutomationElement textBlock1 
    = wpfRoot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "TimeBlock"));
                    AutomationElement textBlock2 
    = wpfRoot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "TimeBlock"));
                    
    for (int i = 0; i < 100; i++)
                    {
                        
    string cachedName = textBlock1.Cached.Name;
                        
    string uncachedName = textBlock2.Current.Name;
                        Console.WriteLine(
    "=================");
                        Console.WriteLine(
    "Cached Name is {0}", cachedName);
                        Console.WriteLine(
    "UnCached Name is {0}", uncachedName);
                        System.Threading.Thread.Sleep(
    300);
                    }
                }

                Console.WriteLine(
    "Test finishes...................");
            }
        }

    测试演示2: timing issue导致的问题和三种应对方法: Sleep/Polling/Event:

    代码
    class DemoDelayedWindow
        {
            
    static DateTime eventStartTime;

            
    public static void NoUISyncLeadToErrorDemo()
            {
                CacheRequest cacheRequest 
    = new CacheRequest();
                cacheRequest.TreeScope 
    = TreeScope.Element;
                cacheRequest.Add(AutomationElement.NameProperty);

                
    using (cacheRequest.Activate())
                {
                    AutomationElement wpfRoot 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "Window1"));
                    AutomationElement btnOpenNewWindow 
    = wpfRoot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "ButtonOpenFlashWindow"));
                    InvokePattern invokPtn 
    = (InvokePattern)btnOpenNewWindow.GetCurrentPattern(InvokePattern.Pattern);
                    invokPtn.Invoke();
                    Console.WriteLine(
    "Button Clicked...");
                    AutomationElement newWindow 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "FlashWindow"));
                    Console.WriteLine(newWindow.Current.Name);
                }

                Console.WriteLine(
    "Test finishes...................");
            }

            
    public static void SimpleSleepSyncDemo()
            {
                DateTime startTime 
    = DateTime.Now;

                CacheRequest cacheRequest 
    = new CacheRequest();
                cacheRequest.TreeScope 
    = TreeScope.Element;
                cacheRequest.Add(AutomationElement.NameProperty);

                
    using (cacheRequest.Activate())
                {
                    AutomationElement wpfRoot 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "Window1"));
                    AutomationElement btnOpenNewWindow 
    = wpfRoot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "ButtonOpenFlashWindow"));
                    InvokePattern invokPtn 
    = (InvokePattern)btnOpenNewWindow.GetCurrentPattern(InvokePattern.Pattern);
                    invokPtn.Invoke();
                    Console.WriteLine(
    "Button Clicked...");
                    Console.WriteLine(
    "Sleeping 6 seconds to wait...");
                    System.Threading.Thread.Sleep(
    1000 * 6);
                    AutomationElement newWindow 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "FlashWindow"));
                    Console.WriteLine(newWindow.Current.Name);
                }

                Console.WriteLine(
    "Test finishes...................");
                Console.WriteLine(
    "Test cost {0} seconds", (DateTime.Now - startTime).TotalSeconds);
            }

            
    public static void PollingSyncDemo()
            {
                DateTime startTime 
    = DateTime.Now;
                CacheRequest cacheRequest 
    = new CacheRequest();
                cacheRequest.TreeScope 
    = TreeScope.Element;
                cacheRequest.Add(AutomationElement.NameProperty);

                
    using (cacheRequest.Activate())
                {
                    AutomationElement wpfRoot 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "Window1"));
                    AutomationElement btnOpenNewWindow 
    = wpfRoot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "ButtonOpenFlashWindow"));
                    InvokePattern invokPtn 
    = (InvokePattern)btnOpenNewWindow.GetCurrentPattern(InvokePattern.Pattern);
                    invokPtn.Invoke();
                    Console.WriteLine(
    "Button Clicked...");

                    
    int timeout = 10 * 1000;
                    
    while (true)
                    {
                        AutomationElement newWindow 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "FlashWindow"));
                        
    if (newWindow == null)
                        {
                            Console.WriteLine(
    "Cannot find expected window. Sleep for a short time");
                            System.Threading.Thread.Sleep(
    500);
                            timeout 
    -= 300;
                            
    if (timeout <= 0)
                            {
                                
    throw new TimeoutException("Window probing process times out after 10 seconds.");
                            }
                        }
                        
    else
                        {
                            Console.WriteLine(newWindow.Current.Name);
                            
    break;
                        }
                    }

                }

                Console.WriteLine(
    "Test finishes...................");
                Console.WriteLine(
    "Test cost {0} seconds", (DateTime.Now - startTime).TotalSeconds);
            }

            
    public static void EventSyncDemo()
            {
                eventStartTime 
    = DateTime.Now;
                CacheRequest cacheRequest 
    = new CacheRequest();
                cacheRequest.TreeScope 
    = TreeScope.Element;
                cacheRequest.Add(AutomationElement.NameProperty);

                
    using (cacheRequest.Activate())
                {
                    AutomationElement wpfRoot 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "Window1"));
                    AutomationElement btnOpenNewWindow 
    = wpfRoot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "ButtonOpenFlashWindow"));
                    InvokePattern invokPtn 
    = (InvokePattern)btnOpenNewWindow.GetCurrentPattern(InvokePattern.Pattern);
                    Console.WriteLine(
    "Register Event");
                    AutomationEventHandler eventHandler 
    = new AutomationEventHandler(OnWindowOpenOrClose);
                    Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, eventHandler);
                    Automation.AddAutomationEventHandler(WindowPattern.WindowClosedEvent, AutomationElement.RootElement, TreeScope.Subtree, eventHandler);

                    invokPtn.Invoke();
                    Console.WriteLine(
    "Button Clicked and Wait...");
                    Console.ReadLine();
                }
            }

            
    static void OnWindowOpenOrClose(object src, AutomationEventArgs e)
            {
                Console.WriteLine(
    "OnWindowOpenOrClose event triggers");
                
    if (e.EventId != WindowPattern.WindowOpenedEvent)
                {
                    Console.WriteLine(
    "It is NOT WindowOpenedEvent.Ignore");
                    
    return;
                }

                AutomationElement sourceElement;
                
    try
                {
                    sourceElement 
    = src as AutomationElement;
                    
    if (sourceElement.Current.AutomationId == "FlashWindow")
                    {
                        Console.WriteLine(sourceElement.Current.Name);
                    }
                }

                
    catch (ElementNotAvailableException)
                {
                    
    return;
                }

                Console.WriteLine(
    "Test finishes...................");
                Console.WriteLine(
    "Test cost {0} seconds", (DateTime.Now - eventStartTime).TotalSeconds);
            }
    }

    测试演示3: 通过Waiter Pattern来简化timing issue的处理:

    代码
    class SimpleWaiter
        {
            
    private AutomationEvent _eventId;
            
    private AutomationElement _element;
            
    private TreeScope _scope;
            
    private System.Threading.AutoResetEvent _event;
            
    private Condition _condition;
            
    private AutomationEventHandler _eventHandler;

            
    public SimpleWaiter(AutomationEvent eventId, AutomationElement element, TreeScope scope, Condition condition)
            {
                
    this._eventId = eventId;
                
    this._element = element;
                
    this._scope = scope;
                
    this._condition = condition;
                _event 
    = new System.Threading.AutoResetEvent(false);
                _eventHandler 
    = new AutomationEventHandler(Handler);
                Automation.AddAutomationEventHandler(_eventId, _element, _scope, _eventHandler);
            }

            
    void Handler(object src, AutomationEventArgs e)
            {            
                AutomationElement sourceElement;
                sourceElement 
    = src as AutomationElement;  
                var finditem 
    = sourceElement.FindFirst(TreeScope.Element, _condition);
                
    if (finditem != null && finditem.Equals(sourceElement))
                {                
                    _event.Set();
                    Automation.RemoveAutomationEventHandler(_eventId, _element, _eventHandler);
                }            
            }

            
    public void Wait(int timeOut)
            {
                _event.WaitOne(timeOut);
            }

         public static void WaiterDemo()
            {
                DateTime startTime 
    = DateTime.Now;
                CacheRequest cacheRequest 
    = new CacheRequest();
                cacheRequest.TreeScope 
    = TreeScope.Element;
                cacheRequest.Add(AutomationElement.NameProperty);

                
    using (cacheRequest.Activate())
                {
                    AutomationElement wpfRoot 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "Window1"));
                    AutomationElement btnOpenNewWindow 
    = wpfRoot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "ButtonOpenFlashWindow"));
                    InvokePattern invokPtn 
    = (InvokePattern)btnOpenNewWindow.GetCurrentPattern(InvokePattern.Pattern);

                    SimpleWaiter waiter 
    = new SimpleWaiter(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "FlashWindow"));

                    invokPtn.Invoke();
                    Console.WriteLine(
    "Button Clicked and Wait...");
                    waiter.Wait(
    1000 * 1000);

                    AutomationElement newWindow 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "FlashWindow"));
                    Console.WriteLine(newWindow.Current.Name);


                    Console.WriteLine(
    "Test finishes...................");
                    Console.WriteLine(
    "Test cost {0} seconds", (DateTime.Now - startTime).TotalSeconds);
                }
            }
        } 

    测试演示3: 如何模拟真实的鼠标click, 以及如何确保测试目标位于前台:

    代码
    [StructLayout(LayoutKind.Sequential)]
        
    public struct HARDWAREINPUT
        {
            
    public uint msg;
            
    public ushort paramL;
            
    public ushort paramH;
        }

        [StructLayout(LayoutKind.Sequential)]
        
    public struct KEYBDINPUT
        {
            
    public ushort virtualKeyCode;
            
    public ushort scanCode;
            
    public uint flags;
            
    public uint time;
            
    public IntPtr extraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        
    public struct MOUSEINPUT
        {
            
    public int dx;
            
    public int dy;
            
    public uint mouseData;
            
    public uint flags;
            
    public uint time;
            
    public IntPtr extraInfo;
        }


        [StructLayout(LayoutKind.Explicit)]
        
    public struct InputTypeUnion
        {
            
    // Fields
            [FieldOffset(0)]
            
    public HARDWAREINPUT hi;
            [FieldOffset(
    0)]
            
    public KEYBDINPUT ki;
            [FieldOffset(
    0)]
            
    public MOUSEINPUT mi;
        }

        [StructLayout(LayoutKind.Sequential)]
        
    public struct INPUT
        {
            
    public uint type;
            
    public InputTypeUnion data;
        }

        
    class Clicker
        {
            [DllImport(
    "user32.dll")]
            
    static extern uint SendInput(uint inputCount, ref INPUT inputs, int inputSize);

            
    static public void Click(Point point)
            {            
                MovePointTo (point.X,point.Y);            
                Click();
            }

            
    static public Point GetClickPoint(AutomationElement ele)
            {            
                Point clickablePt;
                
    if(ele.TryGetClickablePoint(out clickablePt))
                {
                    
    return clickablePt;
                }
                var boundingRect 
    = ele.Current.BoundingRectangle;           
                
    return new Point(boundingRect.X + (boundingRect.Width / 2), boundingRect.Y + (boundingRect.Height / 2));            
            }

            
    static void MovePointTo(double absX, double absY)
            {
                INPUT input 
    = new INPUT();
                var virtualScreen 
    = System.Windows.Forms.SystemInformation.VirtualScreen;
                absX 
    = (((absX - virtualScreen.X) + 0.5* 65536.0/ ((double)virtualScreen.Width);
                absY 
    = (((absY - virtualScreen.Y) + 0.5* 65536.0/ ((double)virtualScreen.Height);
                input.type 
    = 0;
                input.data.mi.dx 
    = (int)absX;
                input.data.mi.dy 
    = (int)absY;
                input.data.mi.flags 
    = 0xc001;
                SendInput(
    1ref input, Marshal.SizeOf(input));
            }

            
    static void MouseDown()
            {
                INPUT input 
    = new INPUT();
                input.type 
    = 0;
                input.data.mi.flags 
    = 2//DOWN
                input.data.mi.mouseData |= 1;
                SendInput(
    1ref input, Marshal.SizeOf(input));
            }

            
    static void MouseUp()
            {
                INPUT input 
    = new INPUT();
                input.type 
    = 0;
                input.data.mi.flags 
    = 4//UP
                input.data.mi.mouseData |= 1;
                SendInput(
    1ref input, Marshal.SizeOf(input));
            }

            
    static void Click()
            {
                MouseDown();
                MouseUp();
            }
        }
     
    代码
    public static void ClickWithWaiterDemo()
            {
                DateTime startTime 
    = DateTime.Now;
                CacheRequest cacheRequest 
    = new CacheRequest();
                cacheRequest.TreeScope 
    = TreeScope.Element;
                cacheRequest.Add(AutomationElement.NameProperty);

                
    using (cacheRequest.Activate())
                {
                    AutomationElement wpfRoot 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "Window1"));
                    WindowPattern wndptn 
    = (WindowPattern)wpfRoot.GetCurrentPattern(WindowPattern.Pattern);

                    var currentStates 
    = wndptn.Current.WindowVisualState;
                    
    if (currentStates != WindowVisualState.Minimized)
                    {
                        wndptn.SetWindowVisualState(currentStates);
                    }
                    
    else
                    {
                        wndptn.SetWindowVisualState(WindowVisualState.Normal);
                    }
                        
                    AutomationElement btnOpenNewWindow 
    = wpfRoot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "ButtonOpenFlashWindow"));
                    InvokePattern invokPtn 
    = (InvokePattern)btnOpenNewWindow.GetCurrentPattern(InvokePattern.Pattern);

                    SimpleWaiter waiter 
    = new SimpleWaiter(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "FlashWindow"));
                    var poi 
    = Clicker.GetClickPoint(btnOpenNewWindow);
                    Clicker.Click(poi);
                    
    //invokPtn.Invoke();
                    Console.WriteLine("Button Clicked and Wait...");
                    waiter.Wait(
    1000 * 1000);

                    AutomationElement newWindow 
    = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "FlashWindow"));
                    Console.WriteLine(newWindow.Current.Name);

                    Console.WriteLine(
    "Test finishes...................");
                    Console.WriteLine(
    "Test cost {0} seconds", (DateTime.Now - startTime).TotalSeconds);
                }
            }

    测试演示4,5演示WaitForReady以及简单的Engine实现, 代码比较多, 就请自己下载吧.

     https://files.cnblogs.com/lixiong/UIAutoDemo.zip

  • 相关阅读:
    移动端图片懒加载插件
    Animate.css 教程
    git使用图解
    React-Native学习指南
    react-native 环境配置及hello world
    修改文件后浏览器自动刷新解决方案
    react-native 布局基础
    MongoDB数据库安装及配置环境(windows10系统)
    MongoDb windows环境安装,附百度云链接
    常用的几类npm依赖包管理
  • 原文地址:https://www.cnblogs.com/lixiong/p/1740335.html
Copyright © 2011-2022 走看看