启用控件的编码的 UI 测试
如果实现用于编码的 UI 测试支持结构,可用于您的控件可以更方便地测试。 可以将增大级别增量支持。 您可以通过支持录制和播放的和属性验证启动。 在能够生成允许编码的 UI 测试生成器识别该控件的自定义特性,并提供自定义选件类访问从生成的代码的那些属性。 您还可以帮助编码的 UI 测试生成器获取事件由距离中记录的事件目的环境的方法。
本主题内容:
通过实现辅助功能支持录制和播放的和属性验证
编码的 UI 测试生成器有关遇到记录期间然后生成代码时播放该会话的控件中获取信息。 如果控件不支持辅助功能,则编码的 UI 测试生成器将收到事件 (如鼠标单击) 使用屏幕坐标。 测试时播放,生成的代码将发出在同一屏幕坐标的那些鼠标单击。 如果控件在屏幕上的一个不同位置出现,测试时播放,生成的代码不能执行对控件的该事件。 这可能导致失败,如果测试在不同的屏幕配置来播放,在不同的环境,或者,在对 UI 格式背后的更改。
如果实现辅助功能,不过,编码的 UI 测试生成器将使用该获取有关控件的信息,该录制测试并生成代码。 然后,那么,当您运行测试,生成的代码将重播这些事件您的控件,因此,即使其他位置在用户界面。 使用您的控件,基本测试的属性作者还可以创建断言。
支持录制和播放属性、验证和导航 windows 窗体控件
如以下过程所述,为控件实现辅助功能和详细介绍了 AccessibleObject。
实现从 Control.ControlAccessibleObject派生的选件类,并重写 AccessibilityObject 属性返回您的选件类对象。
public partial class ChartControl : UserControl { // Overridden to return the custom AccessibleObject for the control. protected override AccessibleObject CreateAccessibilityInstance() { return new ChartControlAccessibleObject(this); } // Inner class ChartControlAccessibleObject represents accessible information // associated with the ChartControl and is used when recording tests. public class ChartControlAccessibleObject : ControlAccessibleObject { ChartControl myControl; public ChartControlAccessibleObject(ChartControl ctrl) : base(ctrl) { myControl = ctrl; } } }
重写可访问对象的 Role、State、GetChild 和 GetChildCount 属性和方法。
实现子控件的另一个辅助对象并重写子控件的 AccessibilityObject 属性返回该辅助对象。
重写 Bounds、Name、Parent、Role、State、Navigate和 Select 属性和方法子控件的可访问性对象的。
备注
本主题从在 AccessibleObject 的可访问性在该的示例在此过程中,然后生成开始其余程序。如果要创建辅助示例的一个有效的版本,请创建一个控件个应用程序之间的示例代码替换 Program.cs 的代码。您需要添加对辅助功能、System.Drawing 和 System.Windows.Forms 的引用。您应更改辅助功能的 嵌入互操作类型 到错误消除生成警告。可以更改项目的输出类型从控件个应用程序到 windows 应用程序,以便控件台未显示窗口,当您运行应用程序。
通过实现属性提供程序支持自定义验证特性
一旦实现了一个基本用于记录支持,并且播放和属性验证,可以将您的可用编码的 UI 通过实现 UITestPropertyProvider 插件测试的控件的自定义属性。 例如,下面的过程创建允许编码的 UI 测试访问图表控件的 CurveLegend 子控件的状态属性的一个属性提供程序。
支持自定义验证特性
重写曲线声明可访问对象的 Description 属性通过在声明字符串的丰富的属性值,分离主要声明 (以及,如果您实现多个属性) 分号 (;)。
public class CurveLegendAccessibleObject : AccessibleObject { // add the state property value to the description public override string Description { get { // Add “;” and the state value to the end // of the curve legend’s description return "CurveLegend; " + State.ToString(); } } }
创建 UI 通过创建选件类库项目来测试您的控件的扩展程序包并添加对辅助功能、Microsoft.VisualStudio.TestTools.UITesting、Microsoft.VisualStudio.TestTools.UITest.Common 和 Microsoft.VisualStudio.TestTools.Extension。 更改辅助功能的 嵌入互操作类型 为错误。
添加从 UITestPropertyProvider派生的属性提供程序选件类。
using System; using System.Collections.Generic; using Accessibility; using Microsoft.VisualStudio.TestTools.UITesting; using Microsoft.VisualStudio.TestTools.UITest.Extension; using Microsoft.VisualStudio.TestTools.UITesting.WinControls; using Microsoft.VisualStudio.TestTools.UITest.Common; namespace ChartControlExtensionPackage { public class ChartControlPropertyProvider : UITestPropertyProvider { } }
通过将属性名和属性说明符实现属性提供程序在 Dictionary<TKey, TValue>。
// Define a map of property descriptors for CurveLegend private static Dictionary<string, UITestPropertyDescriptor> curveLegendPropertiesMap = null; private static Dictionary<string, UITestPropertyDescriptor> CurveLegendPropertiesMap { get { if (curveLegendPropertiesMap == null) { UITestPropertyAttributes read = UITestPropertyAttributes.Readable | UITestPropertyAttributes.DoNotGenerateProperties; curveLegendPropertiesMap = new Dictionary<string, UITestPropertyDescriptor> (StringComparer.OrdinalIgnoreCase); curveLegendPropertiesMap.Add("State", new UITestPropertyDescriptor(typeof(string), read)); } return curveLegendPropertiesMap; } } // return the property descriptor public override UITestPropertyDescriptor GetPropertyDescriptor(UITestControl uiTestControl, string propertyName) { return CurveLegendPropertiesMap[propertyName]; } // return the property names public override ICollection<string> GetPropertyNames(UITestControl uiTestControl) { if (uiTestControl.ControlType.NameEquals("Chart") || uiTestControl.ControlType.NameEquals("Text")) { // the keys of the property map are the collection of property names return CurveLegendPropertiesMap.Keys; } // this is not my control throw new NotSupportedException(); } // Get the property value by parsing the accessible description public override object GetPropertyValue(UITestControl uiTestControl, string propertyName) { if (String.Equals(propertyName, "State", StringComparison.OrdinalIgnoreCase)) { object[] native = uiTestControl.NativeElement as object[]; IAccessible acc = native[0] as IAccessible; string[] descriptionTokens = acc.accDescription.Split(new char[] { ';' }); return descriptionTokens[1]; } // this is not my control throw new NotSupportedException(); }
重写 UITestPropertyProvider.GetControlSupportLevel 指示您的程序集提供控件特定于您的控件及其子控件支持。
public override int GetControlSupportLevel(UITestControl uiTestControl) { // For MSAA, check the control type if (string.Equals(uiTestControl.TechnologyName, "MSAA", StringComparison.OrdinalIgnoreCase) && (uiTestControl.ControlType == "Chart"||uiTestControl.ControlType == "Text")) { return (int)ControlSupport.ControlSpecificSupport; } // This is not my control, so return NoSupport return (int)ControlSupport.NoSupport; }
重写 Microsoft.VisualStudio.TestTools.UITesting.UITestPropertyProvider剩余的抽象方法。
public override string[] GetPredefinedSearchProperties(Type specializedClass) { throw new NotImplementedException(); } public override Type GetSpecializedClass(UITestControl uiTestControl) { throw new NotImplementedException(); } public override Type GetPropertyNamesClassType(UITestControl uiTestControl) { throw new NotImplementedException(); } public override void SetPropertyValue(UITestControl uiTestControl, string propertyName, object value) { throw new NotImplementedException(); } public override string GetPropertyForAction(UITestControl uiTestControl, UITestAction action) { throw new NotImplementedException(); } public override string[] GetPropertyForControlState(UITestControl uiTestControl, ControlStates uiState, out bool[] stateValues) { throw new NotImplementedException(); }
添加从 UITestExtensionPackage派生的扩展程序包选件类。
using System; using Microsoft.VisualStudio.TestTools.UITesting; using Microsoft.VisualStudio.TestTools.UITest.Extension; using Microsoft.VisualStudio.TestTools.UITest.Common; namespace ChartControlExtensionPackage { internal class ChartControlExtensionPackage : UITestExtensionPackage { } }
定义程序集的 UITestExtensionPackage 属性。
[assembly: Microsoft.VisualStudio.TestTools.UITest.Extension.UITestExtensionPackage( "ChartControlExtensionPackage", typeof(ChartControlExtensionPackage.ChartControlExtensionPackage))] namespace ChartControlExtensionPackage { …
在扩展程序包选件类,重写返回属性提供程序选件类的 UITestExtensionPackage.GetService,当属性提供程序请求。
internal class ChartControlExtensionPackage : UITestExtensionPackage { public override object GetService(Type serviceType) { if (serviceType == typeof(UITestPropertyProvider)) { if (propertyProvider == null) { propertyProvider = new ChartControlPropertyProvider(); } return propertyProvider; } return null; } private UITestPropertyProvider propertyProvider = null; }
重写 UITestExtensionPackage剩余的抽象方法和属性。
public override void Dispose() { } public override string PackageDescription { get { return "Supports coded UI testing of ChartControl"; } } public override string PackageName { get { return "ChartControl Test Extension"; } } public override string PackageVendor { get { return "Microsoft (sample)"; } } public override Version PackageVersion { get { return new Version(1, 0); } } public override Version VSVersion { get { return new Version(10, 0); } }
生成的二进制文件并将其复制到 %ProgramFiles%\共享 common\Microsoft\VSTT\10.0\UITestExtensionPackages。
备注
此扩展程序包将应用于类型“text”的所有控件。如果测试同一类型的多个控件,则需要单独测试扩展程序包部署的它们,并管理,在记录测试时。
通过实现选件类支持代码生成访问自定义属性
当编码的 UI 测试时生成器生成参加会议记录的代码,它使用 UITestControl 选件类访问您的控件。
UITestControl uIAText = this.UIItemWindow.UIChartControlWindow.UIAText;
Assert.AreEqual(this.AssertMethod3ExpectedValues.UIATextState, uIAText.GetProperty("State").ToString());
如果实现一个属性提供程序提供对控件的自定义特性,您可以添加用于访问这些属性的专用选件类,以便生成的代码简化。
ControlLegend uIAText = this.UIItemWindow.UIChartControlWindow.UIAText;
Assert.AreEqual(this.AssertMethod3ExpectedValues.UIATextState, uIAText.State);
添加专用选件类访问您的控件
实现从 WinControl 派生的选件类并添加控件的类型到构造函数的搜索属性集合。
public class CurveLegend:WinControl { public CurveLegend(UITestControl c) : base(c) { // The curve legend control is a “text” type of control SearchProperties.Add( UITestControl.PropertyNames.ControlType, "Text"); } }
为控件实现自定义属性作为选件类的属性。
public virtual string State { get { return (string)GetProperty("State"); } }
重写您的属性提供程序的 UITestPropertyProvider.GetSpecializedClass 方法返回新的选件类的类型曲线声明子控件的。
public override Type GetSpecializedClass(UITestControl uiTestControl) { if (uiTestControl.ControlType.NameEquals("Text")) { // This is text type of control. For my control, // that means it’s a curve legend control. return typeof(CurveLegend); } // this is not a curve legend control return null; }
重写您的属性提供程序的 GetPropertyNamesClassType 方法返回新的选件类的 PropertyNames 方法的类型。
public override Type GetPropertyNamesClassType(UITestControl uiTestControl) { if (uiTestControl.ControlType.NameEquals("Text")) { // This is text type of control. For my control, // that means it’s a curve legend control. return typeof(CurveLegend.PropertyNames); } // this is not a curve legend control return null; }
通过实现操作筛选器支持目的感知操作
当 Visual Studio 录制测试时,它会获取鼠标和键盘事件。 但是,在某些情况下,该事件的目的在鼠标和键盘事件系列可能会丢失。 例如,在中,如果控件支持自动完成,因此同一组中,和键盘事件可能产生不同的值,在不同的环境中播放。 可以将用单个操作替换键盘和鼠标事件系列的操作筛选器插件。 这样,您就可以替换鼠标和键盘事件来得出的值的选择在设置值的单个操作。 实现保护代码的 UI 由自动差异测试从一个环境到另一个。
支持目的感知操作
实现从派生 UITestActionFilter,重写属性 ApplyTimeout、Category、Enabled、FilterType、Group 和 Name的操作筛选器选件类。
internal class MyActionFilter : UITestActionFilter { // If the user actions we are aggregating exceeds the time allowed, // this filter is not applied. (The timeout is configured when the // test is run.) public override bool ApplyTimeout { get { return true; } } // Gets the category of this filter. Categories of filters // are applied in priority order. public override UITestActionFilterCategory Category { get { return UITestActionFilterCategory.PostSimpleToCompoundActionConversion; } } public override bool Enabled { get { return true; } } public override UITestActionFilterType FilterType { // This action filter operates on a single action get { return UITestActionFilterType.Unary; } } // Gets the name of the group to which this filter belongs. // A group can be enabled/disabled using configuration file. public override string Group { get { return "ChartControlActionFilters"; } } // Gets the name of this filter. public override string Name { get { return "Convert Double-Click to Single-Click"; } }
重写 ProcessRule。 此处示例 realpces 与一个 click 事件的双击事件。
public override bool ProcessRule(IUITestActionStack actionStack) { if (actionStack.Count > 0) { MouseAction lastAction = actionStack.Peek() as MouseAction; if (lastAction != null) { if (lastAction.UIElement.ControlTypeName.Equals( ControlType.Text.ToString(), StringComparison.OrdinalIgnoreCase)) { if(lastAction.ActionType == MouseActionType.DoubleClick) { // Convert to single click lastAction.ActionType = MouseActionType.Click; } } } } // Do not stop aggregation return false; }
添加操作筛选器。您的扩展程序包 GetService 方法。
public override object GetService(Type serviceType) { if (serviceType == typeof(UITestPropertyProvider)) { if (propertyProvider == null) { propertyProvider = new PropertyProvider(); } return propertyProvider; } else if (serviceType == typeof(UITestActionFilter)) { if (actionFilter == null) { actionFilter = new RadGridViewActionFilter(); } return actionFilter; } return null; }
生成的二进制文件并将它们复制 %ProgramFiles%\common files\Microsoft shared\VSTT\10.0\UITestExtensionPackages。
备注
操作筛选器不依赖于辅助功能实现或属性提供程序。
调试您的属性提供程序或操作筛选器
您的属性提供程序和操作筛选器在加载,并且是代码的负责 UI 测试进程中的生成器与您的应用程序的扩展程序包实现。
要调试属性提供程序或事件可筛选
生成您的扩展程序包复制的调试版本 .dll 和 .pdb files %ProgramFiles%\common files\Microsoft shared\VSTT\10.0\UITestExtensionPackages。
运行您的应用程序 (不是调试器)。
运行编码的 UI 测试生成器。
codedUITestBuilder.exe /standalone
将调试器附加到 codedUITestBuilder 处理。
在代码中设置断点。
在编码的 UI 测试生成器,创建断言执行您的属性提供程序和记录事件实现自己的操作筛选器。
外部资源
指南
测试使用 Visual Studio 进行附带的 2012 版–第 2 章:单元测试:测试。