zoukankan      html  css  js  c++  java
  • .Net软件UI界面测试自动化--UIAutomation技术

    在目前进行软件测试时,都或多或少的引入了自动化测试的概念,而且市面上也有好多软件自动化方面相关的工具,比如QTP,比如LoadRunner,但是这些工具要么售价不菲,要么对某些方面功能支持的不够全面,那么我们在引入软件自动化测试时,都需要考虑哪些方面呢?当然是最符合自己项目的工具最合适,同时费用也比较低,那么除了市面上这些商业软件外,还有没有哪些方法可以自己动手来做软件的自动化测试呢?答案是肯定的.
          本文将介绍实现软件自动化测试其中一种测试方法------UIAutomation技术,当然,此种方法仅限于对.Net软件使用.

          反射技术具体是什么原理,本文将不做任何介绍,大家可以去网上搜索一下,有很多这方面的文章介绍,本文只介绍如何使用UIAutomation技术进行.NET软件的UI界面的自动化测试.

          废话少说,多做实事!(本文所有代码均在VS2008环境下测试通过)

          一. 创建待测试程序

              1. 启动VS2008,建立一个C#的WinForm工程,并将工程文件名命名为AUT(Application Under Test)

              2. 创建的Form上的按钮布局,如下图所示

                  

              3. 一个菜单(包含一个以及菜单File以及一个二级菜单Exit),一个TextBox,一个ComboBox,一个Button以及一个ListBox

            private System.Windows.Forms.MenuStrip menuStrip1;
    private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
    private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
    private System.Windows.Forms.TextBox textBox1;
    private System.Windows.Forms.ComboBox comboBox1;
    private System.Windows.Forms.Button button1;
    private System.Windows.Forms.ListBox listBox1;
                  4. 给Button按钮添加一个消息响应函数    

           private void button1_Click(object sender, EventArgs e)
    {
    string tb = textBox1.Text;
    string cb = comboBox1.Text;

    if (tb == cb)
    {
    listBox1.Items.Add("Result is a tie");
    }
    else if (tb == "paper" && cb == "rock" ||
    tb == "rock" && cb == "scissors" ||
    tb == "scissors" && cb == "paper")
    {
    listBox1.Items.Add("The TextBox wins");
    }
    else
    {
    listBox1.Items.Add("The ComboBox wins");
    }
    }
               5. 给Exit菜单添加一个消息响应函数       
            private void exitToolStripMenuItem_Click(object sender, EventArgs e)
    {
    Application.Exit();
    }
            6.给ComboBox控件添加三个Item,分别为paper,rock,scissions
            7. 编译待测试程序,生成文件名为AUT.exe的待测试程序

        二. 创建测试程序  
            1. 启动VS2008,创建一个C#控制台程序,并命名为AutomationUITest

            2. 在引用中添加以下三个类: UIAutomationClient, UIAutomationClientsideProviders以及UIAutomationTypes

            3. 在工程中添加以下using语句


           using System;
           using System.Windows.Automation;
           using System.Threading;
           using System.Diagnostics;
           using System.IO;
            4. 定义启动测试程序以及获取窗体句柄的函数

            ///<summary>
    ///根据传入的路径启动相应的可执行程序,并返回进程ID
    ///</summary>
    public static Int32 StartExe(string strExePath)
    {
    if (null == strExePath)
    {
    return 0;
    }

    Process ps = Process.Start(strExePath);
    Thread.Sleep(3000);

    return ps.Id;
    }

    ///<summary>
    ///根据进程ID,查找相应窗体,并返回窗体句柄
    ///</summary>
    public static AutomationElement GetWindowHandle(Int32 pid, int iWaitSecond)
    {
    AutomationElement targetWindow = null;
    int iWaitTime = 0;

    try
    {
    Process ps = Process.GetProcessById(pid);

    targetWindow = AutomationElement.FromHandle(ps.MainWindowHandle);

    while (null == targetWindow)
    {
    if (iWaitTime > iWaitSecond)
    {
    break;
    }

    Thread.Sleep(500);

    targetWindow = AutomationElement.FromHandle(ps.MainWindowHandle);
    }

    return targetWindow;
    }
    catch (System.Exception ex)
    {
    string msg = "没有找到指定的窗口,请确认窗口已经启动!";

    throw new InvalidProgramException(msg, ex);
    }
    }
            5.  定义操作TextBox的相关函数

            ///<summary>
    ///根据窗口句柄以及TextEdit的AutomationID,返回TextEdit句柄
    ///</summary>
    public static AutomationElement GetTextEditHandle(AutomationElement parentWindowHandle, string sAutomationID)
    {
    PropertyCondition condition = null;
    PropertyCondition codEdit = null;
    AndCondition andConditon = null;
    AutomationElement targetEditHandle = null;

    try
    {
    if (null == parentWindowHandle)
    {
    return null;
    }

    condition = new PropertyCondition(AutomationElement.AutomationIdProperty, sAutomationID);
    codEdit = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit);
    andConditon = new AndCondition(condition, codEdit);

    targetEditHandle = parentWindowHandle.FindFirst(TreeScope.Children, andConditon);

    return targetEditHandle;
    }
    catch (System.Exception ex)
    {
    string msg = "没有找到指定的TextEdit,请确认TextEdit的AutomationID是否正确!";

    throw new InvalidProgramException(msg, ex);
    }
    }

    ///<summary>
    ///根据TextEdit句柄,在TextEdit内填写数据
    ///只能设置单行输入的TextEdit
    ///</summary>
    public static bool SetTextEditData(AutomationElement TextEditHandle, string strData)
    {
    ValuePattern vpTextEdit = null;

    if (!TextEditHandle.Current.IsEnabled)
    {
    throw new InvalidOperationException("The control is not enabled. ");
    }

    if (!TextEditHandle.Current.IsKeyboardFocusable)
    {
    throw new InvalidOperationException("The control is not focusable. ");
    }

    vpTextEdit = TextEditHandle.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
    if (null == vpTextEdit)
    {
    return false;
    }

    if (vpTextEdit.Current.IsReadOnly)
    {
    throw new InvalidOperationException("The control is read-only.");
    }

    vpTextEdit.SetValue(strData);

    return true;
    }
            6. 定义操作ComboBox的相关函数

            ///<summary>
    ///根据窗口句柄以及ComboBox控件AutomationID,返回该ComboBox控件句柄
    ///</summary>
    public static AutomationElement GetComboBoxHandle(AutomationElement parentWindowHandle, string sAutomationID)
    {
    AutomationElement ComboBoxHandle = null;
    PropertyCondition NameCondition = null;
    PropertyCondition TypeCondition = null;
    AndCondition andCondition = null;

    if (null == parentWindowHandle || null == sAutomationID)
    {
    return null;
    }

    NameCondition = new PropertyCondition(AutomationElement.AutomationIdProperty, sAutomationID);
    TypeCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ComboBox);
    andCondition = new AndCondition(NameCondition, TypeCondition);

    ComboBoxHandle = parentWindowHandle.FindFirst(TreeScope.Children, andCondition);
    if (null == ComboBoxHandle)
    {
    return null;
    }

    return ComboBoxHandle;
    }

    ///<summary>
    ///根据ComboBox控件句柄,设置数据
    ///</summary>
    public static bool SetComboBoxItemData(AutomationElement ComboBoxHandle, string strData)
    {
    AutomationElement TextEditHandle = null;
    PropertyCondition TypeCondition = null;
    ValuePattern vpTextPattern = null;

    if (null == ComboBoxHandle || null == strData)
    {
    return false;
    }

    TypeCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit);

    TextEditHandle = ComboBoxHandle.FindFirst(TreeScope.Children, TypeCondition);
    if (null == TextEditHandle)
    {
    return false;
    }

    if (!TextEditHandle.Current.IsEnabled)
    {
    throw new InvalidOperationException("The control is not enabled. ");
    }

    if (!TextEditHandle.Current.IsKeyboardFocusable)
    {
    throw new InvalidOperationException("The control is not focusable. ");
    }

    vpTextPattern = TextEditHandle.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
    if (null == vpTextPattern)
    {
    return false;
    }

    if (vpTextPattern.Current.IsReadOnly)
    {
    throw new InvalidOperationException("The control is read-only.");
    }

    vpTextPattern.SetValue(strData);

    return true;
    }
            7.  定义操作Button的相关函数

            ///<summary>
    ///根据窗口句柄以及Button的AutomationID,返回Button的句柄
    ///</summary>
    public static AutomationElement GetButtonHandle(AutomationElement parentWindowHandle, string sAutomationID)
    {
    PropertyCondition condition = null;
    PropertyCondition codButton = null;
    AndCondition andConditon = null;
    AutomationElement targetButtonHandle = null;

    try
    {
    if (null == parentWindowHandle)
    {
    return null;
    }

    condition = new PropertyCondition(AutomationElement.AutomationIdProperty, sAutomationID);
    codButton = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button);
    andConditon = new AndCondition(condition, codButton);

    targetButtonHandle = parentWindowHandle.FindFirst(TreeScope.Children, andConditon);

    return targetButtonHandle;
    }
    catch (System.Exception ex)
    {
    string msg = "没有找到指定的按钮,请确认按钮AutomationID是否正确!";

    throw new InvalidProgramException(msg, ex);
    }
    }

    ///<summart>
    ///根据Button按钮句柄,进行鼠标左键单击
    ///</summary>
    public static bool ButtonLeftClick(AutomationElement ButtonHandle)
    {
    object objButton = null;
    InvokePattern ivkpButton = null;

    try
    {
    if (null == ButtonHandle)
    {
    return false;
    }

    if (!ButtonHandle.TryGetCurrentPattern(InvokePattern.Pattern, out objButton))
    {
    return false;
    }

    ivkpButton = (InvokePattern)objButton;

    ivkpButton.Invoke();

    return true;
    }
    catch (System.Exception ex)
    {
    string msg = "鼠标左键单击失败!";

    throw new InvalidProgramException(msg, ex);
    }
    }
            8. 定义操作ListBox的相关函数

            ///<summary>
    ///根据窗口句柄以及ListBox控件AutomationID,返回该ListBox控件句柄
    ///</summary>
    public static AutomationElement GetListBoxHandle(AutomationElement parentWindowHandle, string sAutomationID)
    {
    AutomationElement ListBoxHandle = null;
    PropertyCondition NameCondition = null;
    PropertyCondition TypeCondition = null;
    AndCondition andCondition = null;

    if (null == parentWindowHandle || null == sAutomationID)
    {
    return null;
    }

    NameCondition = new PropertyCondition(AutomationElement.AutomationIdProperty, sAutomationID);
    TypeCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.List);
    andCondition = new AndCondition(NameCondition, TypeCondition);

    ListBoxHandle = parentWindowHandle.FindFirst(TreeScope.Children, andCondition);
    if (null == ListBoxHandle)
    {
    return null;
    }

    return ListBoxHandle;
    }

    ///<summary>
    ///根据ListBox控件句柄以及ItemCount,选择该Item
    ///</summary>
    public static string GetListBoxItemName(AutomationElement ListBoxHandle, int iItemCount)
    {
    AutomationElementCollection ListBoxHandleCollection = null;
    PropertyCondition TypeCondition = null;

    if (null == ListBoxHandle || 0 > iItemCount)
    {
    return null;
    }

    TypeCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem);

    ListBoxHandleCollection = ListBoxHandle.FindAll(TreeScope.Children, TypeCondition);
    if (null == ListBoxHandleCollection)
    {
    return null;
    }

    if (iItemCount >= ListBoxHandleCollection.Count)
    {
    return null;
    }

    return ListBoxHandleCollection[iItemCount].Current.Name;
    }
            9. 定义操作菜单的相关函数

            ///<summary>
    ///根据窗口句柄,以及MenuBar控件AutomationID,返回该MenuBar控件句柄
    ///</summary>
    public static AutomationElement GetMenuBarHandle(AutomationElement parentWindow, string sAutomationID)
    {
    AutomationElement MBHandle = null;
    PropertyCondition NameCondition = null;
    PropertyCondition TypeCondition = null;
    AndCondition andCondition = null;

    if (null == parentWindow || null == sAutomationID)
    {
    return null;
    }

    NameCondition = new PropertyCondition(AutomationElement.AutomationIdProperty, sAutomationID);
    TypeCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.MenuBar);
    andCondition = new AndCondition(NameCondition, TypeCondition);

    MBHandle = parentWindow.FindFirst(TreeScope.Children, andCondition);
    if (null == MBHandle)
    {
    return null;
    }

    return MBHandle;
    }

    ///<summary>
    ///根据MenuBar控件句柄以及一级菜单名称,弹出一级菜单
    ///</summary>
    private static AutomationElement PopupMenuBarItem(AutomationElement MBHandle, string FirMenuTitle)
    {
    InvokePattern IPMenu = null;
    AutomationElement MenuHandle = null;
    PropertyCondition NameCondition = null;
    PropertyCondition TypeCondition = null;
    AndCondition andCondition = null;

    if (null == MBHandle || null == FirMenuTitle)
    {
    return null;
    }

    NameCondition = new PropertyCondition(AutomationElement.NameProperty, FirMenuTitle);
    TypeCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.MenuItem);
    andCondition = new AndCondition(NameCondition, TypeCondition);

    MenuHandle = MBHandle.FindFirst(TreeScope.Children, andCondition);
    if (null == MenuHandle)
    {
    return null;
    }

    IPMenu = MenuHandle.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
    if (null == IPMenu)
    {
    return null;
    }

    IPMenu.Invoke();

    return MenuHandle;
    }

    ///<summary>
    ///根据MenuBar控件句柄以及传入的菜单名称,选择相应的菜单
    ///传入的菜单名称,必须以空字符串结束
    ///</summary>
    public static bool SelectMenuBarItem(AutomationElement MBHandle, string[] strTitle)
    {
    AutomationElement MenuItemHandle = null;

    MenuItemHandle = MBHandle;

    foreach (string str in strTitle)
    {
    if ("" == str)
    {
    break;
    }

    MenuItemHandle = PopupMenuBarItem(MenuItemHandle, str);
    if (null == MenuItemHandle)
    {
    return false;
    }

    Thread.Sleep(400);
    }

    return true;
    }
            10.  添加测试代码

            static void Main(string[] args)
    {
    string path = Directory.GetCurrentDirectory() + "\AUT.exe";

    try
    {
    Console.WriteLine(" Start Application Under Test Exe");
    Int32 ProcessId = StartExe(path);
    Console.WriteLine("Application Under Test ProcessID: " + ProcessId.ToString());

    Console.WriteLine(" Get Main Window Handle");
    AutomationElement mwh = GetWindowHandle(ProcessId, 3000);
    Console.WriteLine("Main Window Handle: " + mwh.Current.NativeWindowHandle.ToString());

    Console.WriteLine(" Get TextBox Handle");
    AutomationElement tbh = GetTextEditHandle(mwh, "textBox1");
    Console.WriteLine("TextBox Handle: " + tbh.Current.NativeWindowHandle.ToString());

    Console.WriteLine(" Get ComboBox Handle");
    AutomationElement cbh = GetComboBoxHandle(mwh, "comboBox1");
    Console.WriteLine("ComboBox Handle: " + cbh.Current.NativeWindowHandle.ToString());

    Console.WriteLine(" Get Button Handle");
    AutomationElement bth = GetButtonHandle(mwh, "button1");
    Console.WriteLine("Button Handle: " + bth.Current.NativeWindowHandle.ToString());

    Console.WriteLine(" Get ListBox Handle");
    AutomationElement lbh = GetListBoxHandle(mwh, "listBox1");
    Console.WriteLine("ListBox Handle: " + lbh.Current.NativeWindowHandle.ToString());

    Console.WriteLine(" Set TextBox Value");
    SetTextEditData(tbh, "paper");

    Console.WriteLine(" Set ConboxBox Value");
    SetComboBoxItemData(cbh, "rock");

    Console.WriteLine(" Push Mouse Left button");
    ButtonLeftClick(bth);

    string result = GetListBoxItemName(lbh, 0);
    if (result == "The TextBox wins")
    {
    Console.WriteLine(" Test seceions = PASS");
    }
    else
    {
    Console.WriteLine(" Test seceions = Failed");
    }

    Console.WriteLine(" Get Menu Handle");
    AutomationElement mbh = GetMenuBarHandle(mwh, "menuStrip1");
    Console.WriteLine("Menu Handle: " + mbh.Current.NativeWindowHandle.ToString());

    string[] strTitle = { "File", "Exit", "" };

    Console.WriteLine(" Close Application Under Test in 3 Seconds....");
    Thread.Sleep(3000);
    SelectMenuBarItem(mbh, strTitle);

    Console.ReadLine();
    }
    catch (System.Exception ex)
    {
    Console.WriteLine(" Error msg: " + ex.Message);
    }
    }
            11.  编译测试程序,OK,大功告成
    ————————————————

    原文链接:https://blog.csdn.net/lassewang/article/details/6693917

  • 相关阅读:
    第一次项目总结
    8.16 CSS知识点7
    2016y9m22d 博文分享
    2016y9m8d
    2016y9m7d
    2016y9m6d
    2016y9m5d
    2016.9.2博文分享!
    2016y8m16d
    2016y8m15d
  • 原文地址:https://www.cnblogs.com/soundcode/p/12383194.html
Copyright © 2011-2022 走看看