.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.\n\n");
}

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

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.\n\n");
}

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

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("\nStart Application Under Test Exe");
Int32 ProcessId = StartExe(path);
Console.WriteLine("Application Under Test ProcessID: " + ProcessId.ToString());

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

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

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

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

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

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

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

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

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

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

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

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

Console.ReadLine();
}
catch (System.Exception ex)
{
Console.WriteLine("\nError msg: " + ex.Message);
}
}
        11.  編譯測試程序,OK,大功告成
————————————————

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM