啟用控制項的自動程式碼 UI 測試功能
如果您實作支援自動程式碼 UI 測試架構,您的控制項可以更容易的被測試。 您可以新增支援來增加層級。 您可以從支援錄製、播放和屬性驗證開始。 您可以建置在允許自動程式碼 UI 測試產生器來辨認您控制項的自訂屬性,並提供自訂類別從已產生的程式碼存取這些屬性。 您也可以用較接近正在錄製動作目的方式幫助自動程式碼 UI 測試產生器擷取動作。
本主題內容:
藉由實作協助工具來支援錄製、播放和屬性驗證。
自動程式碼 UI 測試產生器會擷取在記錄期間控制項遇到並產生程式碼來重新執行該工作階段的相關資訊。 如果控制項不支援協助工具,則自動程式碼 UI 測試產生器會利用螢幕座標擷取動作 (例如按一下滑鼠) 。 當測試播放中,產生的程式碼會在相同螢幕座標中執行滑鼠的點擊 。 當測試進行中時,如果控制項出現在螢幕上的不同位置,產生的程式碼不會對控制項執行該動作。 如果測試在不同螢幕設定、不同環境或UI設定後曾有過變更時播放,都可能導致執行失敗。
如果您實作協助工具,因此,自動程式碼 UI 測試產生器會在錄製測試並產生程式碼時,使用協助工具來取得控制項的資訊。 然後,當您執行測試時,產生的程式碼可針對您的控制向重新執行事件物件,即使在使用者介面有其他測試在執行。 測試作者同時也可以使用控制項的基底屬性建立判斷提示。
支援的錄製和播放、屬性驗證和巡覽 Windows Form 控制項
以下程式為如何實作控制項的協助工具,詳細說明則在 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 屬性以傳回的協助工具物件。
覆寫子控制項的存取範圍物件的 BoundsNameParent、、、、、 RoleStateNavigate和 Select 屬性和方法。
注意事項 |
---|
這個主題由下列程式範例開始 AccessibleObject ,然後在其餘的程序中建置。如果您想要建立協助工具範例的可用版本,請建立主控台應用程式,接著用範例程式碼取代 Program.cs 的程式碼。您將需要加入協助工具、System.Drawing 和 System.Windows.Forms 的參考。您應該變更協助工具的 [內嵌 Interop 型別] 至錯誤排除建置警告。您可以從主控台應用程式到 Windows 應用程式變更專案的輸出類型,讓主控台視窗不會在您執行應用程式出現。 |
藉由實作屬性提供者來支援自訂屬性驗證。
當您實作基本支援記錄、播放和屬性驗證,您可以透過實作進行 UITestPropertyProvider 插入控制項的自訂屬性至自動程式碼 UI 測試。 例如,下列程序建立屬性提供者以允許自動程式碼 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 的參考。 變更存取範圍的 [內嵌 Interop 型別] 設為 false。
新增從 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 Shared \ 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衍生的篩選條件類別,覆寫屬性 ApplyTimeoutCategoryEnabledFilterTypeGroup 和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。 在此範例中,用單一點擊動作取代按兩下的動作。
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 檔 %ProgramFiles%\ Common Files \ Microsoft Shared \ VSTT \ 10.0 \ UITestExtensionPackages。
執行您的應用程式 (不是在偵錯工具)。
執行自動程式碼 UI 測試建置器
codedUITestBuilder.exe /standalone
將偵錯工具附加至自動程式碼UI測試建置器的處理序中。
在您的程式碼中設定中斷點。
在自動程式碼 UI 測試產生器,建立判斷來執行屬性提供者並且使記錄動作執行動作篩選條件。
外部資源
指引
測試以搭配使用 Visual Studio 2012RC–第 2 章:單元測試:內部測試