使用UI Automation实现自动化测试--4.9 (ScrollPattern)
ScrollPattern
ScrollPattern是用来操作控件的滚动条,目前支持ScrollPattern的控件有ListBox,listView,GridView,TreeView.
ScrollPattern主要方法
1. Scroll 水平和垂直滚动内容区域的可见区域滚动, Scroll有两个参数,其类型为ScrollAmount枚举类型。
2. ScrollHorizontal 按指定的 ScrollAmount 水平滚动内容区域的当前可见区域滚动。
3. ScrollVertical 按指定的 ScrollAmount 垂直滚动内容区域的当前可见区域滚动。
ScrollPattern属性
1. VerticallyScrollable 属性用于判定是否可以垂直滚动。
2. HorizontallyScrollable 属性用于判定是否可以水平滚动。
3. HorizontalScrollPercent 获取当前水平滚动条的位置。
4. VerticalScrollPercent 获取当前垂直滚动条的位置。
下面我们通过一个实例来演示自动化测试中如何使用ScrollPattern来测试GridView中滚动条的方法:
Code
1using System;
2using System.Text;
3using System.Diagnostics;
4using System.Threading;
5using System.Windows.Automation;
6
7namespace UIATest
8{
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");
14 int processId = process.Id;
15 Thread.Sleep(1000);
16
17 ScrollPattern#region ScrollPattern
18 AutomationElement element = FindElementById(processId, "listview1");
19 AutomationElementCollection elementCollection=element.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty,ControlType.DataItem));
20
21 ScrollPattern scrollPattern = GetScrollPattern(element);
22
23 if (scrollPattern.Current.VerticallyScrollable)
24 {
25 while (elementCollection[22].Current.IsOffscreen)
26 {
27 scrollPattern.ScrollVertical(ScrollAmount.LargeIncrement);
28 }
29 }
30 #endregion
31
32 }
33
34 /**//// <summary>
35 /// Get the automation elemention of current form.
36 /// </summary>
37 /// <param name="processId">Process Id</param>
38 /// <returns>Target element</returns>
39 public static AutomationElement FindWindowByProcessId(int processId)
40 {
41 AutomationElement targetWindow = null;
42 int count = 0;
43 try
44 {
45 Process p = Process.GetProcessById(processId);
46 targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
47 return targetWindow;
48 }
49 catch (Exception ex)
50 {
51 count++;
52 StringBuilder sb = new StringBuilder();
53 string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();
54 if (count > 5)
55 {
56 throw new InvalidProgramException(message, ex);
57 }
58 else
59 {
60 return FindWindowByProcessId(processId);
61 }
62 }
63 }
64
65
66 /**//// <summary>
67 /// Get the automation element by automation Id.
68 /// </summary>
69 /// <param name="windowName">Window name</param>
70 /// <param name="automationId">Control automation Id</param>
71 /// <returns>Automatin element searched by automation Id</returns>
72 public static AutomationElement FindElementById(int processId, string automationId)
73 {
74 AutomationElement aeForm = FindWindowByProcessId(processId);
75 AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
76 new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
77 return tarFindElement;
78 }
79
80 GetScrollPattern helper#region GetScrollPattern helper
81 /**//// <summary>
82 /// Get ScrollPattern
83 /// </summary>
84 /// <param name="element">AutomationElement instance</param>
85 /// <returns>ScrollPattern instance</returns>
86 public static ScrollPattern GetScrollPattern(AutomationElement element)
87 {
88 object currentPattern;
89 if (!element.TryGetCurrentPattern(ScrollPattern.Pattern, out currentPattern))
90 {
91 throw new Exception(string.Format("Element with AutomationId '{0}' and Name '{1}' does not support the ScrollPattern.",
92 element.Current.AutomationId, element.Current.Name));
93 }
94 return currentPattern as ScrollPattern;
95 }
96
97 #endregion
98 }
99}
100
1using System;
2using System.Text;
3using System.Diagnostics;
4using System.Threading;
5using System.Windows.Automation;
6
7namespace UIATest
8{
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 Process process = Process.Start(@"F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe");
14 int processId = process.Id;
15 Thread.Sleep(1000);
16
17 ScrollPattern#region ScrollPattern
18 AutomationElement element = FindElementById(processId, "listview1");
19 AutomationElementCollection elementCollection=element.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty,ControlType.DataItem));
20
21 ScrollPattern scrollPattern = GetScrollPattern(element);
22
23 if (scrollPattern.Current.VerticallyScrollable)
24 {
25 while (elementCollection[22].Current.IsOffscreen)
26 {
27 scrollPattern.ScrollVertical(ScrollAmount.LargeIncrement);
28 }
29 }
30 #endregion
31
32 }
33
34 /**//// <summary>
35 /// Get the automation elemention of current form.
36 /// </summary>
37 /// <param name="processId">Process Id</param>
38 /// <returns>Target element</returns>
39 public static AutomationElement FindWindowByProcessId(int processId)
40 {
41 AutomationElement targetWindow = null;
42 int count = 0;
43 try
44 {
45 Process p = Process.GetProcessById(processId);
46 targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
47 return targetWindow;
48 }
49 catch (Exception ex)
50 {
51 count++;
52 StringBuilder sb = new StringBuilder();
53 string message = sb.AppendLine(string.Format("Target window is not existing.try #{0}", count)).ToString();
54 if (count > 5)
55 {
56 throw new InvalidProgramException(message, ex);
57 }
58 else
59 {
60 return FindWindowByProcessId(processId);
61 }
62 }
63 }
64
65
66 /**//// <summary>
67 /// Get the automation element by automation Id.
68 /// </summary>
69 /// <param name="windowName">Window name</param>
70 /// <param name="automationId">Control automation Id</param>
71 /// <returns>Automatin element searched by automation Id</returns>
72 public static AutomationElement FindElementById(int processId, string automationId)
73 {
74 AutomationElement aeForm = FindWindowByProcessId(processId);
75 AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
76 new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
77 return tarFindElement;
78 }
79
80 GetScrollPattern helper#region GetScrollPattern helper
81 /**//// <summary>
82 /// Get ScrollPattern
83 /// </summary>
84 /// <param name="element">AutomationElement instance</param>
85 /// <returns>ScrollPattern instance</returns>
86 public static ScrollPattern GetScrollPattern(AutomationElement element)
87 {
88 object currentPattern;
89 if (!element.TryGetCurrentPattern(ScrollPattern.Pattern, out currentPattern))
90 {
91 throw new Exception(string.Format("Element with AutomationId '{0}' and Name '{1}' does not support the ScrollPattern.",
92 element.Current.AutomationId, element.Current.Name));
93 }
94 return currentPattern as ScrollPattern;
95 }
96
97 #endregion
98 }
99}
100
XAML源码:
Code
1<Window x:Class="WpfApp.GridView"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 Title="GridView" Height="280" Width="467">
5 <Grid>
6 <!--将鼠标放在方框的边缘点击就会产生相应的分割线生成Grid.RowDefinitions-->
7 <Grid.RowDefinitions>
8 <!--Auto,实际作用就是取实际控件所需的最小值;值为*或N*,实际作用就是取尽可能大的值;数字,绝对尺寸-->
9 <RowDefinition Height="*" />
10 <RowDefinition Height="auto" MinHeight="95" />
11 <RowDefinition Height="22" />
12 </Grid.RowDefinitions>
13 <ListView Name="listview1" MinWidth="280" Grid.RowSpan="2" MouseMove="listview1_MouseMove">
14 <ListView.View>
15 <GridView x:Name="gridView1">
16 <GridViewColumn Header="EmployeeID" DisplayMemberBinding="{Binding Path=EmployeeID}"></GridViewColumn>
17 <GridViewColumn Header="FirstName" DisplayMemberBinding="{Binding Path=FirstName}"></GridViewColumn>
18 <GridViewColumn Header="LastName" DisplayMemberBinding="{Binding Path=LastName}"></GridViewColumn>
19 <GridViewColumn Header="Address" DisplayMemberBinding="{Binding Path=Address}"></GridViewColumn>
20 </GridView>
21 </ListView.View>
22 </ListView>
23 <!--Grid.Row="1"用来设置WrapPanel及Button应该在父容器的什么位置-->
24 </Grid>
25
26</Window>
1<Window x:Class="WpfApp.GridView"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 Title="GridView" Height="280" Width="467">
5 <Grid>
6 <!--将鼠标放在方框的边缘点击就会产生相应的分割线生成Grid.RowDefinitions-->
7 <Grid.RowDefinitions>
8 <!--Auto,实际作用就是取实际控件所需的最小值;值为*或N*,实际作用就是取尽可能大的值;数字,绝对尺寸-->
9 <RowDefinition Height="*" />
10 <RowDefinition Height="auto" MinHeight="95" />
11 <RowDefinition Height="22" />
12 </Grid.RowDefinitions>
13 <ListView Name="listview1" MinWidth="280" Grid.RowSpan="2" MouseMove="listview1_MouseMove">
14 <ListView.View>
15 <GridView x:Name="gridView1">
16 <GridViewColumn Header="EmployeeID" DisplayMemberBinding="{Binding Path=EmployeeID}"></GridViewColumn>
17 <GridViewColumn Header="FirstName" DisplayMemberBinding="{Binding Path=FirstName}"></GridViewColumn>
18 <GridViewColumn Header="LastName" DisplayMemberBinding="{Binding Path=LastName}"></GridViewColumn>
19 <GridViewColumn Header="Address" DisplayMemberBinding="{Binding Path=Address}"></GridViewColumn>
20 </GridView>
21 </ListView.View>
22 </ListView>
23 <!--Grid.Row="1"用来设置WrapPanel及Button应该在父容器的什么位置-->
24 </Grid>
25
26</Window>
后台CS源码:
Code
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Windows;
6using System.Windows.Controls;
7using System.Windows.Data;
8using System.Windows.Documents;
9using System.Windows.Input;
10using System.Windows.Media;
11using System.Windows.Media.Imaging;
12using System.Windows.Shapes;
13using System.Data.SqlClient;
14using System.Data;
15
16namespace WpfApp
17{
18 /**//// <summary>
19 /// Interaction logic for GridView.xaml
20 /// </summary>
21 public partial class GridView : Window
22 {
23 public GridView()
24 {
25 InitializeComponent();
26 getData();
27 }
28 SqlDataAdapter sda;
29 DataTable dt;
30 void getData()
31 {
32 //init sqlconnection
33 SqlConnectionStringBuilder connbuilder = new SqlConnectionStringBuilder();
34 connbuilder.DataSource = ".";//本地服务器
35 connbuilder.IntegratedSecurity = true;//Windows集成验证
36 connbuilder.InitialCatalog = "TestDB";//数据库为Northwind
37 SqlConnection conn = new SqlConnection(connbuilder.ConnectionString);
38 sda = new SqlDataAdapter("select EmployeeID,FirstName,LastName,Address from Employees ", conn);
39 SqlCommandBuilder commbuilder = new SqlCommandBuilder(sda);
40 //sda.UpdateCommand = commbuilder.GetUpdateCommand();
41 dt = new DataTable();
42 //sda.AcceptChangesDuringUpdate = true;
43 sda.Fill(dt);
44 listview1.ItemsSource = dt.DefaultView;
45 }
46 }
47}
48
49
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Windows;
6using System.Windows.Controls;
7using System.Windows.Data;
8using System.Windows.Documents;
9using System.Windows.Input;
10using System.Windows.Media;
11using System.Windows.Media.Imaging;
12using System.Windows.Shapes;
13using System.Data.SqlClient;
14using System.Data;
15
16namespace WpfApp
17{
18 /**//// <summary>
19 /// Interaction logic for GridView.xaml
20 /// </summary>
21 public partial class GridView : Window
22 {
23 public GridView()
24 {
25 InitializeComponent();
26 getData();
27 }
28 SqlDataAdapter sda;
29 DataTable dt;
30 void getData()
31 {
32 //init sqlconnection
33 SqlConnectionStringBuilder connbuilder = new SqlConnectionStringBuilder();
34 connbuilder.DataSource = ".";//本地服务器
35 connbuilder.IntegratedSecurity = true;//Windows集成验证
36 connbuilder.InitialCatalog = "TestDB";//数据库为Northwind
37 SqlConnection conn = new SqlConnection(connbuilder.ConnectionString);
38 sda = new SqlDataAdapter("select EmployeeID,FirstName,LastName,Address from Employees ", conn);
39 SqlCommandBuilder commbuilder = new SqlCommandBuilder(sda);
40 //sda.UpdateCommand = commbuilder.GetUpdateCommand();
41 dt = new DataTable();
42 //sda.AcceptChangesDuringUpdate = true;
43 sda.Fill(dt);
44 listview1.ItemsSource = dt.DefaultView;
45 }
46 }
47}
48
49
数据库及数据库表源码:
Code
1USE [master]
2GO
3/**//****** Object: Database TestDB Script Date: 10/17/2009 16:08:09 ******/
4IF EXISTS (SELECT name FROM sys.databases WHERE name = N'TestDB')
5DROP DATABASE [TestDB]
6CREATE DATABASE TestDB ON PRIMARY
7( NAME = N'TestDB', FILENAME = N'C:\TestDB.mdf' , SIZE = 2688KB , MAXSIZE = UNLIMITED, FILEGROWTH = 80KB )
8 LOG ON
9( NAME = N'TestDB_log', FILENAME = N'C:\TestDB.ldf' , SIZE = 1024KB , MAXSIZE = UNLIMITED, FILEGROWTH = 10%)
10GO
11
12use TestDB
13
14CREATE TABLE [dbo].[Employees](
15 [EmployeeID] [int] IDENTITY(1,1) primary key NOT NULL,
16 [LastName] [varchar](20) NOT NULL,
17 [FirstName] [varchar](10) NOT NULL,
18 [Address] [varchar](60) NULL
19)
20
21GO
22truncate table employees
23declare @i int
24set @i = 1
25while @i<25
26begin
27
28insert into Employees
29(
30 LastName,
31 FirstName,
32 [Address]
33)
34values
35('Kaden'+cast(@i as varchar), 'Kang'+cast(@i as varchar), 'Nanjing, Jiangsu, China'+cast(@i as varchar))
36set @i=@i+1
37end
38
39
1USE [master]
2GO
3/**//****** Object: Database TestDB Script Date: 10/17/2009 16:08:09 ******/
4IF EXISTS (SELECT name FROM sys.databases WHERE name = N'TestDB')
5DROP DATABASE [TestDB]
6CREATE DATABASE TestDB ON PRIMARY
7( NAME = N'TestDB', FILENAME = N'C:\TestDB.mdf' , SIZE = 2688KB , MAXSIZE = UNLIMITED, FILEGROWTH = 80KB )
8 LOG ON
9( NAME = N'TestDB_log', FILENAME = N'C:\TestDB.ldf' , SIZE = 1024KB , MAXSIZE = UNLIMITED, FILEGROWTH = 10%)
10GO
11
12use TestDB
13
14CREATE TABLE [dbo].[Employees](
15 [EmployeeID] [int] IDENTITY(1,1) primary key NOT NULL,
16 [LastName] [varchar](20) NOT NULL,
17 [FirstName] [varchar](10) NOT NULL,
18 [Address] [varchar](60) NULL
19)
20
21GO
22truncate table employees
23declare @i int
24set @i = 1
25while @i<25
26begin
27
28insert into Employees
29(
30 LastName,
31 FirstName,
32 [Address]
33)
34values
35('Kaden'+cast(@i as varchar), 'Kang'+cast(@i as varchar), 'Nanjing, Jiangsu, China'+cast(@i as varchar))
36set @i=@i+1
37end
38
39
本文简单介绍了ScrollPattern以及使用ScrollPattern来操作垂直水平滚动条。