1、文章一:
題記
本文簡述如何利用appium對Windows桌面應(yīng)用程序進(jìn)行UI自動化測試。
UI自動化測試
所謂UI自動化測試,就是模擬一個用戶,對應(yīng)用程序的UI進(jìn)行操作,以完成特定場景的功能性集成測試。
要對Windows桌面應(yīng)用程序進(jìn)行UI自動化測試,目前可選的技術(shù)主要是兩種:
VS自帶的CodedUI Test和Appium+WinAppDriver。
但是,微軟已經(jīng)宣布VS2019將是帶有CodedUI Test的最后一個版本,且在面對某些復(fù)雜場景的時候有點(diǎn)力不從心。
而Appium作為移動應(yīng)用主流的UI測試工具,已經(jīng)被業(yè)界廣泛采用,且相關(guān)的接口是標(biāo)準(zhǔn)化的,因此微軟對其進(jìn)行了擴(kuò)展(即WinAppDriver),讓Appium可以支持包括Universal Windows Platform (UWP), Windows Forms (WinForms), Windows Presentation Foundation (WPF), and Classic Windows (Win32)之內(nèi)的Windows桌面應(yīng)用。所以采用Appium來作為Windows桌面應(yīng)用程序UI自動化測試的工具是最佳選擇。
要完成UI自動化測試的大致步驟如下(你首先需要一臺Windows 10的PC):
-
準(zhǔn)備好待測試的Windows桌面應(yīng)用程序。
-
到 https://github.com/Microsoft/WinAppDriver/releases 下載WinAppDriver的安裝包,進(jìn)行安裝。并啟用Windows 10的開發(fā)者模式。從安裝目錄(比如:C:\Program Files (x86)\Windows Application Driver)來啟動WinAppDriver。
-
用你喜歡的測試框架創(chuàng)建UnitTest項(xiàng)目,在項(xiàng)目中引用Appium.WebDriver這個Nuget包。
-
編寫測試用例,執(zhí)行測試。
整個用例的編寫也相對簡單:
-
使用DesiredCapabilities來設(shè)定要測試的目標(biāo)應(yīng)用。
-
使用WindowsDriver來聲明測試的會話。
-
通過測試會話查找對應(yīng)的UI元素,對UI元素進(jìn)行SendKeys(模擬填寫內(nèi)容)和Click(模擬點(diǎn)擊)等操作,或者獲取UI元素的相關(guān)Property和Attribute來進(jìn)行驗(yàn)證。
-
編寫測試最挑戰(zhàn)的地方就是在于如何查找到UI元素,我們可以借用Windows SDK里面的inspect.exe這個工具來輔助我們查找。
工具的位置在C:\Program Files (x86)\Windows Kits\10\bin里面的特定版文件夾中。用法是先啟動應(yīng)用程序并導(dǎo)航到待測試的界面,啟動這個工具就會獲得桌面上所有窗口的UI元素層級關(guān)系,并通過焦點(diǎn)等方式導(dǎo)航到要查找的UI元素上。查看相應(yīng)的信息,并采用適合的查找方式。具體的查找方式可見:https://github.com/Microsoft/WinAppDriver#supported-locators-to-find-ui-elements。
選擇適合的查找方式有時候需要多嘗試幾種,有些UI元素只能用特定的方式來查找,比如html的input button只用FindElementByName ,而html的button就可以用FindElementByAccessibilityId 。
測試用例的編寫可以參考WinAppDriver源代碼自帶的Sample,也可以參照我的示例:https://github.com/heavenwing/WindowsAppUITestSample。
在我的這個示例當(dāng)中,目標(biāo)應(yīng)用采用的是Hybrid方式運(yùn)行(即通過WebBrowser來嵌入html,并用C#進(jìn)行行為操作),考慮到這種應(yīng)用程序可能是多個函數(shù)庫組裝在一起,所以測試項(xiàng)目理應(yīng)也是多個項(xiàng)目組合的(即功能函數(shù)庫對應(yīng)一個測試項(xiàng)目),并且其他測試項(xiàng)目可以復(fù)用公共的測試步驟(比如:列表頁面復(fù)用登錄的測試步驟)。
參考
https://www.cnblogs.com/redmoon/p/11401030.html
2、文章二:
參考:https://blog.csdn.net/The_Eyes/article/details/73432716
最近研究自動化測試,看了一下UI Automation的微軟例子,表示太老了,遇到各種問題,
UI Spy 好像已經(jīng)被放棄了,可以用inspect.exe來代替,win10 的路徑為:“C:\Program Files (x86)\Windows Kits\8.1\bin\x64\inspect.exe”
這個用來查詢automationId,
官網(wǎng)是以計(jì)算器例子,下面是在win10 修改后能運(yùn)行版本:
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;
namespace ConsoleApp1
{
class CalcAutomationClient
{
AutomationElement calWindow = null;//計(jì)算器窗口主窗口元素
string resultTextAutoID = "CalculatorResults";
string btn5AutoID = "num5Button";
string btn3AutoID = "num3Button";
string btn2AutoID = "num2Button";
string btnPlusAutoID = "plusButton";
string btnSubAutoId = "94";
string btnEqualAutoID = "equalButton";
static void Main(string[] args)
{
CalcAutomationClient autoClient = new CalcAutomationClient();
AutomationEventHandler eventHandler = new AutomationEventHandler(autoClient.OnWindowOpenOrClose);
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, eventHandler);
Process.Start("calc.exe");
Console.ReadLine();
}
private void OnWindowOpenOrClose(object sender, AutomationEventArgs e)
{
if (calWindow != null)
return;
if (e.EventId != WindowPattern.WindowOpenedEvent)
{
return;
}
if (sender == null)
{
Console.WriteLine("sender is null");
return;
}
Thread.Sleep(1000);//此處必須等待一下,應(yīng)該是計(jì)算器的等待計(jì)算器完全加載,不然控件 找不到
AutomationElement sourceElement = null;
sourceElement = sender as AutomationElement;
Console.WriteLine(sourceElement.Current.Name);
try
{
sourceElement = sender as AutomationElement;
Console.WriteLine(sourceElement.Current.Name);
if (sourceElement.Current.Name == "計(jì)算器")
{
calWindow = sourceElement;
}
}
catch (Exception ex)
{
Console.WriteLine("ex:" + ex.Message);
return;
}
if (calWindow == null)
{
return;
}
ExcuteTest();
}
private void ExcuteTest()
{
ExcuteButtonInvoke(btn2AutoID);
ExcuteButtonInvoke(btnPlusAutoID);
ExcuteButtonInvoke(btn3AutoID);
ExcuteButtonInvoke(btnEqualAutoID);
string rs = GetCurrentResult();
Console.WriteLine(rs);
}
private void ExcuteButtonInvoke(string automationId)
{
Condition conditions = new AndCondition(
new PropertyCondition(AutomationElement.AutomationIdProperty, automationId),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button));
if (calWindow == null)
return;
AutomationElementCollection collection = calWindow.FindAll(TreeScope.Descendants, conditions);
if (collection == null || collection.Count == 0)
return;
AutomationElement btn = collection[0];
if (btn != null)
{
InvokePattern invokeptn = (InvokePattern)btn.GetCurrentPattern(InvokePattern.Pattern);
invokeptn.Invoke();
}
Thread.Sleep(1000);
}
private string GetCurrentResult()
{
Condition conditions = new AndCondition(
new PropertyCondition(AutomationElement.AutomationIdProperty, resultTextAutoID),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text));
AutomationElement text = calWindow.FindAll(TreeScope.Descendants, conditions)[0];
return text.Current.Name;
}
}
}
運(yùn)行結(jié)果:
3、重要資源【實(shí)例】:
1)已驗(yàn)證可用【非常好的例子,便于理解】
C#自動化測試工具編寫(借助API) :https://download.csdn.net/download/luminji/2796362
關(guān)鍵代碼
1)自動化測試程序
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//獲取被測試程序的窗口句柄
IntPtr mainWnd = FindWindow(null, "FormLogin");
List<IntPtr> listWnd = new List<IntPtr>();
//獲取窗體上按鈕的句柄,按鈕上的文字為OK
IntPtr hwnd_button = FindWindowEx(mainWnd, new IntPtr(0), null, "OK");
//獲取窗體上全部的子控件句柄
EnumChildWindows(mainWnd, new CallBack(delegate(IntPtr hwnd, int lParam)
{
listWnd.Add(hwnd);
return true;
}), 0);
foreach (IntPtr item in listWnd)
{
if (item != hwnd_button)
{
char[] UserChar = "StarStar".ToCharArray();
foreach (char ch in UserChar)
{
SendChar(item, ch, 100);
}
}
}
SendMessage(hwnd_button, WM_CLICK, mainWnd, "0");
}
public void SendChar(IntPtr hand, char ch, int SleepTime)
{
PostMessage(hand, WM_CHAR, ch, 0);
System.Threading.Thread.Sleep(SleepTime);
}
public static int WM_CHAR = 0x102;
public static int WM_CLICK = 0x00F5;
[DllImport("User32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,
string lpszClass, string lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern int AnyPopup();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
public static extern int EnumThreadWindows(IntPtr dwThreadId, CallBack lpfn, int lParam);
[DllImport("user32.dll")]
public static extern int EnumChildWindows(IntPtr hWndParent, CallBack lpfn, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Ansi)]
public static extern IntPtr PostMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Ansi)]
public static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr SendMessageA(IntPtr hwnd, int wMsg, int wParam, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr GetParent(IntPtr hWnd);
public delegate bool CallBack(IntPtr hwnd, int lParam);
}
}
2)被測試程序
using System;
using System.Windows.Forms;
namespace WindowsFormsToBeTest
{
public partial class FormLogin : Form
{
public FormLogin()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(textBox1.Text.Trim());
}
}
}
運(yùn)行結(jié)果:
2)未驗(yàn)證
C#借助Code UI Automation實(shí)現(xiàn)黑盒自動化測試工具: https://download.csdn.net/download/luminji/2839416文章來源:http://www.zghlxwxcb.cn/news/detail-791571.html
和上邊的好像一樣:文章來源地址http://www.zghlxwxcb.cn/news/detail-791571.html
到了這里,關(guān)于C#【自動化測試】對Windows桌面應(yīng)用程序進(jìn)行UI自動化測試的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!