.NET自动化测试手记(3)- 查看当前系统安装的更新

这篇主要通过点击窗体按钮、监听窗体和控件的事件实现读取当前系统安装的更新。需要用到UISpy.exe。

主要操作步骤如下:

  1. 运行命令打开"Programs and Features"窗体,同时监听窗体打开的事件
  2. 点击"View installed updates"按钮,跳转到"Installed Updates"窗口,同时监听窗体名字改变的事件
  3. 获取页面加载的进度条并读取进度,需要监听进度条进度发生改变的事件
  4. 获取承载所有更新项的datagrid
  5. 遍历所有更新项并执行操作

以下是需要调用到的功能,先在这里列出来:

获取给定控件里有特定名字的子控件
          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

 

 

posted @ 2012-02-18 16:28  silverbullet11  阅读(827)  评论(0编辑  收藏  举报