Compartir a través de


Habilitar pruebas de IU codificadas en los controles

El control puede probarse con mayor facilidad si se implementa el soporte para el marco de pruebas codificadas de IU.Se pueden agregar niveles de compatibilidad de forma incremental.Se puede comenzar admitiendo la grabación y la reproducción y la validación de propiedad.Puede basarse en ello para permitir que el generador de pruebas codificadas de la interfaz de usuario reconozca las propiedades personalizadas del control y proporcione clases personalizadas para obtener acceso a esas propiedades desde el código generado.También se puede ayudar al generador de pruebas codificadas de la interfaz de usuario a capturar acciones de una manera que es próxima a la intención de la acción que se está registrando.

En este tema:

  1. Admitir la grabación y reproducción y la validación de las propiedades al implementar la accesibilidad

  2. Compatibilidad de validación de propiedad personalizada usando un proveedor de propiedades

  3. Generación de código de soporte implementando una clase para obtener acceso a propiedades personalizadas

  4. Soporte acciones conscientes de intenciones al implementar un filtro de acciones

CUIT_Full

Admitir la grabación y reproducción y la validación de las propiedades al implementar la accesibilidad

El generador de pruebas codificadas de interfaz de usuario captura información acerca de los controles que encuentra durante una grabación y después genera código para reproducir esa sesión.Si el control no admite accesibilidad, el generador de pruebas codificadas de interfaz de usuario capturará acciones (como clics del mouse) mediante las coordenadas de la pantalla.Cuando la prueba se reproduce, el código generado emitirá los clics del mouse en las mismas coordenadas de la pantalla.Si el control aparece en un lugar diferente en la pantalla cuando se reproduce la prueba, el código generado no podrá realizar esa acción en el control.Esto puede producir errores si la prueba se reproduce en diferentes configuraciones de pantalla, en entornos distintos o después de que se hayan realizado cambios en el diseño de la interfaz de usuario.

CUIT_RecordNoSupport

Sin embargo, si implementa accesibilidad, el generador de pruebas codificadas de la interfaz de usuario la utilizará para capturar información sobre el control cuando registra una prueba y genera código.Luego, al ejecutar la prueba, el código generado volverá a producir esos eventos en el control, aunque esté en alguna otra parte en la interfaz de usuario.Los autores de las pruebas también podrán crean aserciones utilizando las propiedades básicas del control.

CUIT_Record

Hh552522.collapse_all(es-es,VS.110).gifPara admitir la grabación y reproducción, la validación de propiedad y la navegación de un control de Windows Forms

Implemente la accesibilidad para el control de acuerdo con el procedimiento siguiente, que se explica detalladamente en AccessibleObject.

CUIT_Accessible

  1. Implemente una clase que se derive de Control.ControlAccessibleObject y reemplace la propiedad AccessibilityObject para devolver un objeto de la clase.

    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;
            }
        }
    }
    
  2. Reemplace las propiedades y métodos del objeto accesible Role, State, GetChild y GetChildCount.

  3. Implemente otro objeto de accesibilidad para el control secundario y reemplace la propiedad AccessibilityObject del control secundario para devolver ese objeto de accesibilidad.

  4. Reemplace las propiedades y métodos del control accesible Bounds, Name, Parent, Role, State, Navigate y Select.

[!NOTA]

Este tema comienza con el ejemplo de accesibilidad en AccessibleObject en este procedimiento y, a continuación, se basa en ello en los procedimientos restantes.Si desea crear una versión operativa del ejemplo de accesibilidad, cree una aplicación de consola y reemplace el código en Program.cs con el código de ejemplo.Necesitará agregar referencias a accesibilidad, System.Drawing y System.Windows.Forms.Debe cambiar los Tipos de interoperabilidad incrustados de accesibilidad a False para eliminar una advertencia de compilación.Puede cambiar el tipo de salida del proyecto desde la aplicación de consola a aplicación Windows de modo que no aparezca una ventana de consola cuando ejecute la aplicación.

Compatibilidad de validación de propiedad personalizada usando un proveedor de propiedades

Una vez que haya implementado la compatibilidad básica para el registro, reproducción y validación de propiedades, puede colocar las propiedades personalizadas del control a disposición de las pruebas de interfaz de usuario programadas implementando un complemento de UITestPropertyProvider.Por ejemplo, el procedimiento siguiente crea un proveedor de propiedades que permite que las pruebas de interfaz de usuario programadas tengan acceso a la propiedad State de los controles secundarios CurveLegend del control chart.

CUIT_CustomProps

Hh552522.collapse_all(es-es,VS.110).gifPara admitir validación de propiedades personalizadas

CUIT_Props

  1. Reemplace la propiedad Description del objeto accesible CurveLegend para pasar valores de propiedad enriquecidos en la cadena de descripción, independiente de la descripción principal (y de si implementa varias propiedades) por punto y coma (;).

    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();
            }
        }
    }
    
  2. Cree un paquete de extensión de pruebas de interfaz de usuario para el control creando un proyecto de biblioteca de clases y agregue referencias a la accesibilidad, Microsoft.VisualStudio.TestTools.UITesting, Microsoft.VisualStudio.TestTools.UITest.Common y Microsoft.VisualStudio.TestTools.Extension.Cambie Incrustar tipos de interoperabilidad de accesibilidad a False.

  3. Agregue una clase de proveedor de la propiedad que derive de 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
        {
        }
    }
    
  4. Implemente el proveedor de propiedades colocando nombres y descriptores de propiedad en 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();
    }
    
  5. Reemplace el método UITestPropertyProvider.GetControlSupportLevel para indicar que el ensamblado proporciona compatibilidad de control específico para el control y sus elementos secundarios.

    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;
    }
    
  6. Reemplace los métodos abstractos restantes de 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();
    }
    
    
    
    
    
  7. Agregue una clase de paquete de extensión que se deriva de 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
        {
        }
    }
    
  8. Defina el atributo UITestExtensionPackage para el ensamblado.

    [assembly: Microsoft.VisualStudio.TestTools.UITest.Extension.UITestExtensionPackage(
                    "ChartControlExtensionPackage",
                    typeof(ChartControlExtensionPackage.ChartControlExtensionPackage))]
    namespace ChartControlExtensionPackage
    {
       …
    
  9. En la clase de paquete de extensión, reemplace el método UITestExtensionPackage.GetService para devolver la clase de proveedor de propiedades cuando se solicita un proveedor de propiedades.

    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;
    }
    
  10. Reemplace los métodos y propiedades abstractos restantes de 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); }
    }
    
  11. Compile los binarios y cópielos a %ProgramFiles%\Common\Microsoft Shared\VSTT\10.0\UITestExtensionPackages.

[!NOTA]

Este paquete de extensión se aplicará a cualquier control que sea de tipo “Text”.Si está probando varios controles del mismo tipo, necesitará probarlos por separado y administrar que paquetes de la extensión se implementan al registrar las pruebas.

Generación de código de soporte implementando una clase para obtener acceso a propiedades personalizadas

Cuando el generador de pruebas de interfaz de usuario programadas genera código de un registro de sesión, usa la clase de UITestControl para obtener acceso a los controles.

UITestControl uIAText = this.UIItemWindow.UIChartControlWindow.UIAText;
Assert.AreEqual(this.AssertMethod3ExpectedValues.UIATextState, uIAText.GetProperty("State").ToString());

Si ha implementado un proveedor de propiedades para proporcionar acceso a las propiedades personalizadas del control, puede agregar una clase especializada que se usa para obtener acceso a esas propiedades para simplificar el código generado.

ControlLegend uIAText = this.UIItemWindow.UIChartControlWindow.UIAText;
Assert.AreEqual(this.AssertMethod3ExpectedValues.UIATextState, uIAText.State);

Hh552522.collapse_all(es-es,VS.110).gifPara agregar una clase especializada para obtener acceso al control

CUIT_CodeGen

  1. Implemente una clase que se derive de WinControl y agregue el tipo de control a la colección de las propiedades de búsqueda en el constructor.

    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");
       }
    }
    
  2. Implemente las propiedades personalizadas del control como propiedades de la clase.

    public virtual string State
    {
        get
        {
            return (string)GetProperty("State");
        }
    }
    
  3. Reemplace el método UITestPropertyProvider.GetSpecializedClass del proveedor de propiedades para devolver el tipo de la nueva clase para los controles secundarios de CurveLegend.

    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;
    }
    
  4. Reemplace el método de GetPropertyNamesClassType del proveedor de propiedades para devolver el tipo de método de PropertyName de las nuevas clase.

    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;
    }
    

Soporte acciones conscientes de intenciones al implementar un filtro de acciones

Cuando Visual Studio registra una prueba, captura cada evento del mouse y teclado.Sin embargo, en algunos casos, la intención de la acción se puede perder en la serie de eventos de teclado y de mouse.Por ejemplo, si los soportes de control autocompletar, el mismo conjunto de eventos de teclado y de mouse puede dar lugar a un valor diferente cuando la prueba se reproducen en un entorno diferente.Puede agregar un complemento de filtro de acciones que reemplace la serie de eventos de teclado y mouse con una sola acción.De esta manera, puede reemplazar la serie de eventos del mouse y teclado provocando así la selección de un valor con una única acción que establezca el valor.Haciendo eso protege las pruebas de interfaz de usuario programadas de las diferencias de autocompletar de un entorno a otro.

Hh552522.collapse_all(es-es,VS.110).gifPara admitir acciones conscientes de intención

CUIT_Actions

  1. Implemente una clase de filtro de acción que se derive de UITestActionFilter, reemplazando las propiedades ApplyTimeout, Category, Enabled, FilterType, Group y 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"; }
       }
    
  2. Reemplace ProcessRule.El ejemplo reemplaza una acción de doble clic con una acción de un solo clic.

    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;
    }
    
  3. Agregue el filtro de acción al método GetService del paquete de extensión.

    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;
    }
    
  4. Compile los binarios y cópielos a %ProgramFiles%\Common Files\Microsoft Shared\VSTT\10.0\UITestExtensionPackages.

[!NOTA]

El filtro de acción no depende de la implementación de accesibilidad o proveedor de la propiedades.

Depure su proveedor de propiedades o filtro de acciones.

Los proveedores de propiedades y filtros de acción se implementan en un paquete de extensión que es cargado y ejecutado por el generador de pruebas de interfaz de usuario programadas en un proceso independiente de la aplicación.

Para depurar su proveedor de propiedades o filtro de acciones

  1. Compile la versión de depuración de la copia del paquete de extensión y copie los archivos .dll y .pdb a %ProgramFiles%\Common Files\Microsoft Shared\VSTT\10.0\UITestExtensionPackages.

  2. Ejecute la aplicación (no en el depurador).

  3. Ejecute el constructor de pruebas de interfaz de usuario programadas.

    codedUITestBuilder.exe /standalone

  4. Adjunte manualmente el depurador al proceso codedUITestBuilder.

  5. Establezca puntos de interrupción en el código.

  6. En el generador de pruebas de interfaz de usuario programadas, cree aserciones para utilizar el proveedor de propiedades y acciones de registro para aplicar los filtros de acción.

Recursos Externos

Hh552522.collapse_all(es-es,VS.110).gifGuía

Prueba para la entrega continuo con Visual Studio 2012 – Capítulo 2: Pruebas unitarias: Probando el interior

Vea también

Referencia

AccessibleObject

Conceptos

Comprobar el código usando pruebas de interfaz de usuario codificadas