使用UI Automation实现自动化测试 (InvokePattern)

InvokePattern

InvokePatternUIA中最常用的Pattern之一,WPFWinform中的button控件都支持InvokePattern

InvokePatternInvoke()方法的调用应立即返回,没有出现阻止情况。但是,此行为完全依赖于 Microsoft UI 自动化提供程序实现。在调用 Invoke()会引起阻止问题(如Winform中的模式对话框,但是WPF中的对话框的处理方式和winform不同,所以可以使用Invoke()方法来操作WPF中的模式对话框,因为WPF中的模式对话框不会出现阻止的问题)的情况下,要调用此方法,则需要另起线程来操作。



using System;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;

namespace UIATest
{
     class Program
    {
         static  void Main( string[] args)
        {
            Process process = Process.Start( @" F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe ");
             int processId = process.Id;
            AutomationElement element = FindElementById(processId,  " button1 ");
            InvokePattern currentPattern = GetInvokePattern(element);
            currentPattern.Invoke();
        }

         ///   <summary>
        
///  Get the automation elemention of current form.
        
///   </summary>
        
///   <param name="processId"> Process Id </param>
        
///   <returns> Target element </returns>
         public  static AutomationElement FindWindowByProcessId( int processId)
        {
            AutomationElement targetWindow =  null;
             int count =  0;
             try
            {
                Process p = Process.GetProcessById(processId);
                targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
                 return targetWindow;
            }
             catch (Exception ex)
            {
                count++;
                StringBuilder sb =  new StringBuilder();
                 string message = sb.AppendLine( string.Format( " Target window is not existing.try #{0} ", count)).ToString();
                 if (count >  5)
                {
                     throw  new InvalidProgramException(message, ex);
                }
                 else
                {
                     return FindWindowByProcessId(processId);
                }
            }
        }


         ///   <summary>
        
///  Get the automation element by automation Id.
        
///   </summary>
        
///   <param name="windowName"> Window name </param>
        
///   <param name="automationId"> Control automation Id </param>
        
///   <returns> Automatin element searched by automation Id </returns>
         public  static AutomationElement FindElementById( int processId,  string automationId)
        {
            AutomationElement aeForm = FindWindowByProcessId(processId);
            AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
             new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
             return tarFindElement;
        }

         #region InvokePattern helper
         ///   <summary>
        
///  Get InvokePattern
        
///   </summary>
        
///   <param name="element"> AutomationElement instance </param>
        
///   <returns> InvokePattern instance </returns>
         public  static InvokePattern GetInvokePattern(AutomationElement element)
        {
             object currentPattern;
             if (!element.TryGetCurrentPattern(InvokePattern.Pattern,  out currentPattern))
            {
                 throw  new Exception( string.Format( " Element with AutomationId '{0}' and Name '{1}' does not support the InvokePattern. ",
                    element.Current.AutomationId, element.Current.Name));
            }
             return currentPattern  as InvokePattern;
        }

         #endregion
    }
}

被测程序xaml代码如下:

<Window x:Class="WpfApp.Window1"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    Title
="Window1" Height="219" Width="353">
    
<Grid>
        
<Button Height="23" HorizontalAlignment="Left" Click="button1_Click" Margin="50,0,0,62" Name="button1" VerticalAlignment="Bottom" Width="75">Button</Button>
    
</Grid>
</Window>

对应的cs文件:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp
{
    
/// <summary>
    
/// Interaction logic for Window1.xaml
    
/// </summary>
    public partial class Window1 : Window
    {
        
public Window1()
        {
            InitializeComponent();
        }

        
private void button1_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(
"Use InvokePattern invoke button.");
        }
    }
}

      本文主要针对InvokePattern的Invoke方法来操作button控件。


关于您提到的
在调用 Invoke() 会引起阻止问题

原因是UIAutomation对于WPF的实现是native的, 通信是通过named pipe

对于WinForm等Win32的实现是DCOM Message, 也就是Windows Message, 所以需要message pump

不过无论如何, 把test client中的main thread标记为STAThread, 都因该没有问题

希望作者能多介绍下UI Automation中更多的知识, 比如UI Event怎么用,还有常见的问题, 比如timming issue等

在调用 Invoke() 会引起阻止问题
此问题困扰我很久,谢谢解答,对于UI Automation中的UI Event我接触的比较少,实在抱歉,但我会尽自己最大的努力,还望多多帮忙啊

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值