.NET自动化测试手记(3)- 查看当前系统安装的更新
这篇主要通过点击窗体按钮、监听窗体和控件的事件实现读取当前系统安装的更新。需要用到UISpy.exe。
主要操作步骤如下:
- 运行命令打开"Programs and Features"窗体,同时监听窗体打开的事件
- 点击"View installed updates"按钮,跳转到"Installed Updates"窗口,同时监听窗体名字改变的事件
- 获取页面加载的进度条并读取进度,需要监听进度条进度发生改变的事件
- 获取承载所有更新项的datagrid
- 遍历所有更新项并执行操作
以下是需要调用到的功能,先在这里列出来:
获取给定控件里有特定名字的子控件
public static AutomationElement FindControl(AutomationElement ele, ControlType type, string name)
{
if (ele==null)
{
return null;
}
PropertyCondition nameProperty = new PropertyCondition(AutomationElement.NameProperty, name);
PropertyCondition typeProperty = new PropertyCondition(AutomationElement.ControlTypeProperty, type);
AndCondition andCondition = new AndCondition(nameProperty, typeProperty);
return ele.FindFirst(TreeScope.Subtree, andCondition);
}
获取给定空间里有特定属性的子控件
public static AutomationElement FindControlByType(AutomationElement ele, ControlType type)
{
if (ele==null)
{
return null;
}
PropertyCondition typeProperty = new PropertyCondition(AutomationElement.ControlTypeProperty, type);
return ele.FindFirst(TreeScope.Descendants, typeProperty);
}
获取有特定名字的窗体
public static AutomationElement GetWindowByName(AutomationElement parent, string name)
{
if (parent == null)
{
throw new Exception("Parent element is null!");
}
PropertyCondition nameProperty = new PropertyCondition(AutomationElement.NameProperty, name);
PropertyCondition typeProperty = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window);
AndCondition andCondition = new AndCondition(nameProperty, typeProperty);
return parent.FindFirst(TreeScope.Descendants | TreeScope.Element, andCondition);
}
下面进入正题:
1. 运行命令打开"Programs and Features"窗体,同时监听窗体打开的事件
首先需要声明一个AutomationEventHandler,如下:
static AutomationEventHandler aeHandler = new AutomationEventHandler(OnProgramsWindowOpen); //监听“Programs and Features”窗体打开的事件
打开窗体并监听:
运行命令打开"Programs and Features"窗体,同时开始监听
public void Run()
{
//添加AutomationEventHandler,监听"Programs and Features"的打开事件
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Subtree, aeHandler);
//打开"Programs and Features"
Process.Start("control", “appwiz.cpl”).WaitForExit();
}
2. 点击"View installed updates"按钮,跳转到"Installed Updates"窗口,同时监听窗体名字改变的事件
首先,定义EventHandler
static AutomationPropertyChangedEventHandler propChangedHander = new AutomationPropertyChangedEventHandler(OnNameChanged); //监听窗体名字变化
当aeHandler监听到事件的时候会进入"OnProgramsWindowOpen”方法:
获取并点击"View installed updates"超链接
public static void OnProgramsWindowOpen(object sender,AutomationEventArgs args)
{
//获取窗体
AutomationElement proWindow = sender as AutomationElement;
//获取“View installed updates”超链接
AutomationElement hyperViewUpdates = FindControl(proWindow, ControlType.Hyperlink, "View installed updates");
if (hyperViewUpdates!=null)
{
//添加AutomationPropertyChangedEventHandler,监听窗体名字的变化
Automation.AddAutomationPropertyChangedEventHandler(proWindow, TreeScope.Subtree, propChangedHander, AutomationElementIdentifiers.NameProperty);
//点击超链接
InvokePattern invoke = (InvokePattern)hyperViewUpdates.GetCurrentPattern(InvokePattern.Pattern);
invoke.Invoke();
}
}
3. 获取页面加载的进度条并读取进度,需要监听进度条进度发生改变的事件
声明EventHandler监听进度条的进度:
static AutomationPropertyChangedEventHandler proBarChangedHander = new AutomationPropertyChangedEventHandler(OnValueChanged);
当窗体名称发生改变时开始监听进度条的进度:
查看窗体名称并监听进度条进度
public static void OnNameChanged(object sender, AutomationPropertyChangedEventArgs args)
{
//获取当前窗体
AutomationElement ele = sender as AutomationElement;
if (ele.Current.Name == "Installed Updates")
{
//移除所有EventHandler,以免对后面的handler产生影响。如果没有影响也可以不加这句
Automation.RemoveAllEventHandlers();
Console.WriteLine("Name switched, is {0}", ele.Current.Name);
//等待页面加载进度完成
WaitForLoaded();
}
else
{
Console.WriteLine("Name is {0}", ele.Current.Name);
}
}
监听进度条加载进度
public static bool IsContinueRefresh = true;
private static void WaitForLoaded()
{
//由于窗体名字改变了,需要重新获取名为"Installed Updates"窗体
AutomationElement proWindow = GetWindowByName(AutomationElement.RootElement, "Installed Updates");
Console.WriteLine("Class Name: {0}", proWindow.Current.ControlType.LocalizedControlType);
Console.WriteLine("Handler:{0}", proWindow.Current.NativeWindowHandle.ToString());
if (proWindow != null)
{
//获取进度条
AutomationElement progressBar = FindControlByType(proWindow, ControlType.ProgressBar);
//获取刷新按钮,有的时候可能需要重复刷新进度条才会有明显的(可以监听到的)进度变化。
AutomationElement refreshButton = FindControl(proWindow, ControlType.Button, "Refresh \"Installed Updates\"");
InvokePattern invoke = (InvokePattern)refreshButton.GetCurrentPattern(InvokePattern.Pattern);
//添加监听事件
Automation.AddAutomationPropertyChangedEventHandler(progressBar, TreeScope.Element, proBarChangedHander, RangeValuePattern.ValueProperty);
//不停刷新窗体,直到监听到进度条的变化
while (IsContinueRefresh)
{
Console.WriteLine(refreshButton.Current.Name);
Thread.Sleep(1000);
if (IsContinueRefresh)
{
try
{
Console.WriteLine("Refresh...");
invoke.Invoke();
}
catch
{
Console.WriteLine("Exception, break...");
break;
}
}
else
{
break;
}
}
}
}
4. 读取进度,当进度为100%的时候遍历所有更新项并读取各项的名字
获取更新项并执行操作
public static void OnValueChanged(object sender, AutomationPropertyChangedEventArgs args)
{
// 停止刷新窗体
IsContinueRefresh = false;
//实例化进度条
AutomationElement pb = sender as AutomationElement;
//获取进度条的RangeValuePattern, 方便后面读取进度
RangeValuePattern rangePb = (RangeValuePattern)pb.GetCurrentPattern(RangeValuePattern.Pattern);
double percent=rangePb.Current.Value;
if ( percent == 100)
{
//移除所有的EventHandler,节省系统资源,同时也避免EventHandler之间的影响
Automation.RemoveAllEventHandlers();
//逐级获取控件,直到找到对应的更新列表
AutomationElement proWindow = GetWindowByName(AutomationElement.RootElement, "Installed Updates"); //获取“Installed Updates”窗体元素
AutomationElement datagrid = FindControl(proWindow, ControlType.DataGrid, "Folder View"); //获取更新列表元素
AutomationElementCollection dataItems = datagrid.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.DataItem)); //获取所有更新元素的集合
//遍历所有更新元素并执行操作
foreach (AutomationElement item in dataItems)
{
//将元素滚动到屏幕显示范围之内
ScrollItemPattern scrollPattern = (ScrollItemPattern)item.GetCurrentPattern(ScrollItemPattern.Pattern);
scrollPattern.ScrollIntoView();
//在控制台中显示元素的值
ValuePattern value = (ValuePattern)item.GetCurrentPattern(ValuePattern.Pattern);
Console.WriteLine(value.Current.Value);
}
}
else
{
//显示进度
ShowPercentage(percent);
}
}
模拟进度条
private static void ShowPercentage(double percent)
{
int top = Console.CursorTop;
Console.WriteLine("Current progress is {0}%", percent.ToString());
Console.CursorTop = top;
}
到这里,所要实现的操作就已经完成了。
关于如何确定要监听哪些事件,可以借助UISpy.exe,具体操作如下(以监听进度条进度为例):
首先,打开控制面板,进入到"Installed Updates"页
然后打开UISpy.exe,找到(如果显示的元素没有这么多,可以把窗体调到最前面,然后刷新UISpy.exe)
找到进度条
点击菜单栏监听按钮开始监听(建议取消监听会引起Exception的事件,可以在右边那个按钮"Configure Events"里面设置)
刷新窗体,并观察UISpy.exe “Output”里的变化,可以发现类似下面的文字。这时就可以确定该监听哪些事件,并从哪些属性里面观察变化了。
Property Change Event Time Stamp : 2/18/2012 4:24:42 PM Element : "progress bar" "" Property : RangeValuePatternIdentifiers.ValueProperty New Value : 99 Old Value : null Property Change Event Time Stamp : 2/18/2012 4:24:44 PM Element : "progress bar" "" Property : RangeValuePatternIdentifiers.ValueProperty New Value : 100 Old Value : null