Ejecución de prueba
Automatizar las pruebas de interfaz de usuario de aplicaciones de WPF
James McCaffrey
Descarga de código de la Galería de código de MSDN
Examinar el código en línea
Contenido
La aplicación WPF en prueba
La automatización de la prueba de interfaz de usuario
Palabras finales
En la columna de este mes, muestro cómo escribir automatización de interfaz de usuario de prueba para las aplicaciones de Windows Presentation Foundation (WPF). Aplicaciones WPF utilizan un subsistema de gráficos nuevo, y las técnicas de automatización de interfaz de usuario prueba más tradicionales simplemente no funcionan con las aplicaciones WPF. Afortunadamente, la biblioteca Microsoft UI Automation (MUIA) se diseñó con la automatización de interfaz de usuario de aplicación WPF en mente. También puede utilizar la biblioteca Microsoft UI Automation para probar aplicaciones Win32 clásicos y aplicaciones de .NET de WinForm-basándose en los equipos host que ejecutan sistemas operativos compatibles con Microsoft .NET 3.0 Framework.
En comparación con anteriores alternativas para la automatización de interfaz de usuario, la biblioteca Microsoft UI Automation es más eficaz y más coherente, y después de una curva de aprendizaje inicial, encontrará es mucho más fácil de usar. Esta columna supone que hay algunas básica familiaridad con las aplicaciones de WPF, capacidades de C# nivel intermedios, pero sin experiencia con la biblioteca MUIA.
Una buena forma de mostrar donde me punta es con una captura de pantalla. La imagen en la figura 1 muestra estoy probando una aplicación WPF sencilla pero representativa. La aplicación se denomina CryptoCalc y calcula un hash criptográfico de una cadena de entrada utilizando uno de tres técnicas de hash: MD5 de hash, el hash SHA1 o el cifrado DES.
Figura 1 automatización de interfaz de usuario de WPF Application
El MD5 (Message Digest 5) hash técnica acepta una matriz de bytes arbitrariamente tamaño y devuelve una huella de 16 bytes que puede utilizarse para varios fines de identificación. El SHA1 técnica de hash (seguro algoritmo hash 1) es similar a MD5, excepto que SHA1 utiliza un algoritmo diferente y devuelve una huella 20 bytes. El DES (digital estándar de cifrado) es una técnica cifrado de clave simétrica que también puede utilizarse para generar una matriz de bytes identificación. Cifrado DES-hash devuelve una matriz de bytes que es al menos tan grande como el número de bytes de entrada.
La automatización de prueba de interfaz de usuario que se muestra en la figura 1 se ejecuta a través de una aplicación de consola que inicia la aplicación de prueba; utiliza la biblioteca Microsoft UI Automation para obtener referencias a los controles de aplicación y usuario de la aplicación; y simula un usuario escribir "Hello.", selecciona la opción de cifrado DES y hace clic en el control de botón COMPUTE. La automatización de prueba, a continuación, comprueba el estado resultante de la aplicación en el que se realiza la prueba examinando el control de texto la casilla de resultado para un valor esperado y imprime un paso o fracasan resultado. Captura la captura en la figura 1 sólo antes de la automatización de prueba cerrar la aplicación en el que se realiza la prueba mediante la simulación clics del usuario en el archivo y, a continuación, elementos de menú de salida de pantalla.
En las secciones de esta columna que siguen, brevemente se describen la aplicación WPF CryptoCalc que estoy probando y explica cómo iniciar la aplicación en el que se realiza la prueba, cómo utilizar la biblioteca Microsoft UI Automation para obtener referencias a los controles de aplicación y usuario, cómo simular las acciones del usuario y cómo comprobar el estado de la aplicación. También describiré cómo puede ampliar y modificar el sistema de prueba presentado aquí para satisfacer sus propias necesidades. CREO que encontrará la posibilidad de utilizar la biblioteca Microsoft UI Automation para probar aplicaciones WPF una nueva incorporación al conjunto de la herramienta personales.
La aplicación WPF en prueba
Echemos un vistazo breve a la aplicación WPF en el que se realiza la prueba para que le comprender el objetivo de la automatización de prueba y entender los problemas de diseño que afectan a la interfaz de usuario de prueba de automatización. La aplicación CryptoCalc es una aplicación de usuario sencilla, ventana única, que calcula un hash criptográfico de una cadena. La aplicación acepta una cadena proporcionado por el usuario de hasta 24 caracteres de un control TextBox, convierte la cadena de entrada en una matriz de bytes, calcula uno de los tres tipos de cifrado de los valores de hash de los bytes de entrada y muestra los bytes hash resultantes en un segundo control TextBox.
Diseñó la aplicación de prueba que usa Visual Studio 2008 con C# y se denomina CryptoCalc el proyecto. La plantilla WPF genera una definición de interfaz de usuario de aplicación esqueleto como un archivo XAML:
<Window x:Class="CryptoCalc.Window1"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid></Grid>
</Window>
Observe que la definición de control de ventana de nivel superior no contiene un atributo de nombre. Esto se importante debe, como veremos más adelante, cuando se escribe prueba de automatización, una forma sencilla de obtener una referencia a un control mediante la biblioteca MUIA es acceso a la propiedad AutomationId, que se genera el compilador de atributo de nombre del control. Los controles sin un atributo de nombre de XAML no recibirán una propiedad AutomationId. Esta idea es un ejemplo específico, bajo nivel de la importancia de problemas de diseño de aplicaciones para cosas tales como seguridad, extensibilidad y automatización de pruebas teniendo en cuenta.
A continuación, agrega un control de etiqueta y un control TextBox arrastrando elementos desde el cuadro de herramientas de Visual Studio en la superficie de diseño:
<Label Height="28" HorizontalAlignment="Left"
Margin="10,33,0,0" Name="label1" VerticalAlignment="Top"
Width="120">Enter string:</Label>
<TextBox MaxLength="24" Height="23" Margin="10,57,51,0"
Name="textBox1" VerticalAlignment="Top" />
Tenga en cuenta que de forma predeterminada, estos controles recibir atributos de nombre normales, label1 y textBox1, respectivamente. A continuación, colocan tres controles RadioButton dentro de un control GroupBox. A diferencia del control GroupBox de WinForms anterior, un GroupBox WPF acepta sólo un elemento único, por lo que agrupan los tres controles RadioButton en un único contenedor StackPanel (que puede contener varios elementos):
<GroupBox Header="Crypto Type" Margin="10,91,118,127"
Name="groupBox1">
<StackPanel Height="52" Name="stackPanel1" Width="127">
<RadioButton Height="16" Name="radioButton1" Width="120">
MD5 Hash</RadioButton>
<RadioButton Height="16" Name="radioButton2" Width="120">
SHA1 Hash</RadioButton>
<RadioButton Height="16" Name="radioButton3" Width="120">
DES Encrypt</RadioButton>
</StackPanel>
</GroupBox>
A continuación, colocan un control de botón para activar el cálculo hash de cifrado y un control TextBox para almacenar el resultado en el control principal de Windows:
<Button Height="23" Margin="10,0,0,90" Name="button1"
VerticalAlignment="Bottom" Click="button1_Click"
HorizontalAlignment="Left" Width="89">Compute</Button>
<TextBox Height="63" Margin="10,0,51,13" Name="textBox2"
VerticalAlignment="Bottom" TextWrapping="Wrap" />
Una de las características que realmente me gusta acerca de las aplicaciones de WPF es el nuevo paradigma de control de menú, que, a diferencia de lo que ocurre con los artículos del menú de WinForm, trata los menús y submenús como controles de usuario normal. En primer lugar, arrastra un control de contenedor principal de menú a la parte superior de la aplicación CryptoCalc:
<Menu Height="22" Name="menu1"
VerticalAlignment="Top" IsMainMenu="True" >
</Menu>
Visual Studio 2008 no admite un diseño de arrastrar y colocar para los controles secundarios MenuItem, por lo que agregar Mis elementos de menú al XAML definición archivo manualmente agregando un elemento de menú archivo de nivel superior:
<MenuItem Header="_File">
<MenuItem Header="_New" Name="fileNew" />
<MenuItem Header="_Open" Name="fileOpen" />
<Separator />
<MenuItem Header="E_xit" Name="fileExit"
InputGestureText="Alt-F4" ToolTip="Exit CryptoCalc"
Click="OnFileExit" />
</MenuItem>
Diseño WPF permite la sintaxis de clave de acelerador habitual, como _File. El < Separador o > etiqueta es limpio y fácil. El atributo de información sobre herramientas generará código que muestra un mensaje de ayuda corta cuando el usuario mouses sobre el control de MenuItem asociado. Cuando se compila, el atributo haga clic en OnFileExit generará código de C# que espera un controlador de eventos con esta firma:
public void OnFileExit(object sender, RoutedEventArgs e) {
//...
}
Por lo tanto, después agrega el código de lógica de aplicación normal a la aplicación CryptoCalc, agrega manualmente el controlador de eventos y, a continuación, proporciona funcionalidad colocar this.Close en el cuerpo del método. Tenga en cuenta que los controles de elementos de menú nuevo y abrir no es necesario ningún evento asociado en este momento. Hizo para señalar que a menudo automatización de prueba de interfaz de usuario tiene lugar durante el desarrollo, cuando muchas características de aplicación están incompletas. El diseño de control de ayuda de nivel superior sigue el mismo modelo que el control de archivo:
<MenuItem Header="_Help">
<MenuItem Header="Help Topics" />
<Separator />
<MenuItem Header="About CryptoCalc" />
</MenuItem>
El contenedor de menú y las definiciones de control de MenuItem generará código de C# que a su vez genera la interfaz de usuario que se muestra en la captura de pantalla en la figura 2 . Con el diseño de interfaz de usuario realizado, cambia a través de a la vista Código. A continuación, se ha agregado dos mediante instrucciones utilizando instrucciones generadas por Visual Studio en el archivo Window1.xaml.cs para que tener acceso podría a cifrado clases y métodos sin calificar completamente sus nombres:
using System.Security.Cryptography;
using System.IO;
La Figura 2 menú archivo de aplicación WPF
La funcionalidad principal de la aplicación de CryptoCalc simple está incluida en el método Button1_Click y se muestra la figura 3 . Mi código primero toma el texto del control textBox1 y convierte ese texto en una matriz de bytes. Tenga en cuenta que para mantener el tamaño de mi código de ejemplo se corta, omite la normal de comprobación de errores que desea realizar en un entorno de producción.
Código de aplicación de la figura 3 StatCalc
private void button1_Click(object sender, RoutedEventArgs e)
{
string input = textBox1.Text;
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
if (radioButton1.IsChecked == true) {
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] hashedBytes = md5.ComputeHash(inputBytes);
textBox2.Text = BitConverter.ToString(hashedBytes);
}
else if (radioButton2.IsChecked == true) {
SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
byte[] hashedBytes = sha.ComputeHash(inputBytes);
textBox2.Text = BitConverter.ToString(hashedBytes);
}
else if (radioButton3.IsChecked == true) {
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] blanks = System.Text.Encoding.UTF8.GetBytes(" "); // 8 spaces
des.Key = blanks;
des.IV = blanks;
des.Padding = PaddingMode.Zeros;
MemoryStream ms = new MemoryStream();
CryptoStream cs =
new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(inputBytes, 0, inputBytes.Length);
cs.Close();
byte[] encryptedBytes = ms.ToArray();
ms.Close();
textBox2.Text = BitConverter.ToString(encryptedBytes);
}
}
Las sucursales de lógica de aplicación dependiendo de qué RadioButton control está seleccionado. Curiosamente, dado que la propiedad IsChecked devuelve el tipo? bool (valor booleano que aceptan valores null), tenía que comprobar explícitamente la propiedad de igualdad en true. El código para MD5 y SHA1 hash debe ser no necesita explicación.
El algoritmo de cifrado DES requiere una clave de 64 bits. Debido a estoy utilizando DES para hash en vez de codificación y descodificación, utilizan una clave prueba generada por 8 caracteres de espacio. Cuando se utiliza cifrado de clave simétrica para propósitos de hash, suele utilizar una clave null de {0 x 00, 0 x 00, 0 x 00, 0 x 00, 0 x 00, 0 x 00, 0 x 00, 0 x 00}, pero el objeto DESCryptoServiceProvider indicadores esto como una clave débil conocida y produce una excepción. Utilizo la misma matriz de bytes de espacio en blanco de espacio para proporcionar un valor para el vector de inicialización denominado.
Cifrado DES funciona en bloques de 8 bytes; por lo tanto, especificar PaddingMode.Zeros para que cualquier entrada se se rellenan con ceros para que aparezca el tamaño de la entrada hasta a un múltiplo par de 8 bytes. Tenga en cuenta que no debe utilizar PaddingMode.Zeros para la codificación y descodificación porque relleno con ceros no le permite descifrar (el algoritmo de descifrado no puede determinar que ceros en el cifrado de texto están relleno y que forman parte de la original de texto sin formato).
La automatización de la prueba de interfaz de usuario
Cuando se escribe prueba de automatización mediante la biblioteca Microsoft UI Automation, tiene que saber cómo identificar los controles de la aplicación en el que se realiza la prueba. Una buena forma de hacerlo es utilizar la herramienta UISpy. Para aquellos que no conocen, UISpy es el equivalente WPF de la antigua herramienta Spy ++ y permite examinar propiedades de los componentes de interfaz de usuario de una aplicación WPF. La herramienta UISpy es parte del SDK de Microsoft Windows y está disponible como descarga gratuita de Microsoft.com/downloads .
La captura de pantalla en la figura 4 muestra el resultado de destino en el control de botón de la aplicación CryptoCalc. Desde una perspectiva de automatización de prueba, los campos importantes para identificar los controles de aplicación son el ControlType (ControlType.Edit en este caso), AutomationId (button1) y valores Name (COMPUTE). El campo importante para manipular los controles de aplicación es la lista de ControlPatterns (Invoke).
La figura 4 Examinar controles con UISpy
Probar manualmente incluso esta aplicación CryptoCalc pequeña a través de su interfaz de usuario podría ser aburridos, propensas, mucho tiempo y ineficaz. Se tendrá que escribir una entrada, haga clic en el control de botón COMPUTE, visualmente comprobar la respuesta y registrar manualmente el resultado de aprobación o error. Un método mucho mejor es utilizar la biblioteca Microsoft UI Automation para escribir la automatización de prueba que simula un usuario utiliza la aplicación y, a continuación, determina si la aplicación ha respondido correctamente. Mediante la automatización tediosos casos de prueba, puede liberar tiempo para los más interesantes y útiles manuales casos de prueba en el que su experiencia y intuition desempeñan un papel grande.
La estructura general del instrumento de prueba que creó el resultado que se muestra en la figura 1 se muestra en figura 5 . Inicia Visual Studio 2008 y crea un nuevo programa de aplicación de consola. Usé C#, pero debe podrá convertir mi código de automatización de prueba a .NET de Visual Basic si desea fácilmente. A continuación, agrega referencias de proyecto a las bibliotecas UIAutomationClient.dll y UIAutomationTypes.dll. Estas bibliotecas forman parte de .NET Framework 3.0, pero no son visibles de forma predeterminada para un proyecto de Visual Studio. Las bibliotecas normalmente se encuentran en el directorio c:\Archivos Files\Reference Assemblies\Microsoft\Framework\v3.0. Tenga en cuenta que la biblioteca UIAutomationClient.dll contiene las clases de claves necesarias para la automatización de prueba. La biblioteca UIAutomationTypes.dll contiene varias definiciones de tipo utilizados por la automatización de prueba MUIA.
En la figura 5 interfaz de usuario de prueba de automatización código estructura
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;
namespace Harness {
class Program {
static void Main(string[] args) {
try {
Console.WriteLine("\nBegin WPF UIAutomation test run\n");
// launch CryptoCalc application
// get reference to main Window control
// get references to user controls
// manipulate application
// check resulting state and determine pass/fail
Console.WriteLine("\nEnd automation\n");
}
catch (Exception ex) {
Console.WriteLine("Fatal: " + ex.Message);
}
} // Main()
} // class
} // ns
Para mayor comodidad, PUEDO agregar mediante las instrucciones que señalan al espacio de nombres System.Diagnostics (de manera que fácilmente pueda utilizar la clase Process) y en el espacio de nombres System.Threading (de manera que fácilmente pueda utilizar el método Thread.Sleep()). Como de costumbre con cualquier automatización de prueba, incluyo el instrumento con un bloque try-catch de nivel superior para controlar los errores graves. Mi código de automatización de prueba comienza al iniciar la aplicación en el que se realiza la prueba:
Console.WriteLine("Launching CryptoCalc application");
Process p = null;
p = Process.Start("..\\..\\..\\CryptoCalc\\bin\\Debug\\CryptoCalc.exe");
Ahora, antes de que trata de cualquier automatización de prueba, debe comprobar que el proceso asociado a la aplicación CryptoCalc en el que se realiza la prueba está registrado en el equipo host. Aunque puede pausar mi instrumento de prueba simplemente insertando una instrucción Thread.Sleep, tiene no una buena manera de saber cuánto para hacer una pausa. Un enfoque mejor es usar un retardo de bucle inteligente:
int ct = 0;
do {
Console.WriteLine("Looking for CryptoCalc process. . . ");
++ct;
Thread.Sleep(100);
} while (p == null && ct < 50);
Aquí detenga de 100 milisegundos cada vez que el bucle de retraso. El instrumento termina el bucle de retardo si el objeto de proceso se convierte en no es null, lo que significa que se ha encontrado el proceso, o si el bucle ha ejecutado 50 veces. se encontró la figura 6 muestra cómo puede determinar si el bucle de retraso agotado o el proceso AUT.
Figura 6 Determinación de qué sucedió con
if (p == null)
throw new Exception("Failed to find CryptoCalc process");
else
Console.WriteLine("Found CryptoCalc process");
// Next I fetch a reference to the host machine's Desktop as an
// AutomationElement object:
Console.WriteLine("\nGetting Desktop");
AutomationElement aeDesktop = null;
aeDesktop = AutomationElement.RootElement;
if (aeDesktop == null)
throw new Exception("Unable to get Desktop");
else
Console.WriteLine("Found Desktop\n");
Se puede considerar de todos los controles de la aplicación WPF en el que se realiza la prueba como elementos secundarios del control de ventana de aplicación principal. La ventana principal es un secundario del escritorio global, por lo que necesita una referencia en el escritorio en para obtener una referencia a la aplicación. Ahora utilizar el método FindFirst para adjuntar a la aplicación en el que se realiza la prueba:
AutomationElement aeCryptoCalc = null;
int numWaits = 0;
do {
Console.WriteLine("Looking for CryptoCalc main window. . . ");
aeCryptoCalc = aeDesktop.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.NameProperty, "CryptoCalc"));
++numWaits;
Thread.Sleep(200);
} while (aeCryptoCalc == null && numWaits < 50);
Utilizar la técnica inteligente Retardo de bucle en lugar de la técnica de suspensión arbitrariamente larga. Cuando el control que está buscando está un solo control, se utiliza el método FindFirst. FindFirst acepta dos argumentos. El primero es un valor de ámbito. Los tres tipos de ámbito más comunes utilizados en la automatización de prueba son TreeScope.Children, TreeScope.Descendants y TreeScope.Parent. Dado que la aplicación CryptoCalc es un elemento secundario directo del escritorio, utilizar el ámbito TreeScope.Children.
El segundo argumento FindFirst es un objeto que representa la información que identifica el control que está buscando. Aquí especificar que ESTOY buscando un control que tiene una propiedad de nombre con el valor "CryptoCalc". He podría también utilizado la propiedad AutomationId, que describiré en breve. Ahora compruebe que realmente tiene una referencia al control ventana de aplicación principal:
if (aeCryptoCalc == null)
throw new Exception("Failed to find CryptoCalc main window");
else
Console.WriteLine("Found CryptoCalc main window");
Una vez que tenga la aplicación, puede utilizar su referencia para obtener referencias a todos los controles de usuario que la automatización de prueba se manipular o examinar. SE inicia por tomar el control de botón:
Console.WriteLine("\nGetting all user controls");
AutomationElement aeButton = null;
aeButton = aeCryptoCalc.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.NameProperty, "Compute"));
if (aeButton == null)
throw new Exception("No compute button");
else
Console.WriteLine("Got Compute button");
Usar el mismo modelo que utiliza para obtener una referencia a la ventana principal; aquí el control de botón es un secundario directo del control de aplicación de ventana principal. Porque el control de botón es un control estático, no es necesario utilizar la técnica de retardo de bucle antes de obtener acceso a la referencia al control. En el caso de los controles dinámicos, se debe utilizar la técnica Retardo de bucle.
A continuación, desea obtener referencias a los dos controles TextBox. Aunque los dos controles TextBox tienen nombres textBox1 y textBox2, los controles no reciben las propiedades de nombre, por lo que no se puede usar el mismo modelo NameProperty que utiliza para el control de botón. Sin embargo, los controles TextBox recibir una propiedad AutomationId que puede utilizar para obtener una referencia a los controles, tales como:
aeTextBox1 = aeCryptoCalc.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.AutomationIdProperty, "textBox1"));
En su lugar, decidí usar un enfoque diferente, principalmente para la demostración. En lugar de identificar un solo control utilizando la propiedad de nombre del control, utilice el método FindAll para recuperar una colección de controles por tipo de control. Resulta que los controles TextBox son tipos de ControlType.Edit, por lo que mi código toma todos los controles TextBox:
AutomationElementCollection aeAllTextBoxes = null;
aeAllTextBoxes = aeCryptoCalc.FindAll(TreeScope.Children,
new PropertyCondition(AutomationElement.ControlTypeProperty,
ControlType.Edit));
if (aeAllTextBoxes == null)
throw new Exception("No textboxes collection");
else
Console.WriteLine("Got textboxes collection");
Una vez que tiene esta colección puede obtener acceso a cada control TextBox utilizando una indización de matriz:
AutomationElement aeTextBox1 = null;
AutomationElement aeTextBox2 = null;
aeTextBox1 = aeAllTextBoxes[0];
aeTextBox2 = aeAllTextBoxes[1];
if (aeTextBox1 == null || aeTextBox2 == null)
throw new Exception("TextBox1 or TextBox2 not found");
else
Console.WriteLine("Got TextBox1 and TextBox2");
En general, obtener referencias de control mediante la propiedad Name o la propiedad AutomationId es un enfoque mejor que el uso de ControlType, pero en algunos casos puede no que tenga ninguna opción. A continuación, obtener una referencia al control RadioButton que desee utilizar en el escenario de prueba:
AutomationElement aeRadioButton3 = null;
aeRadioButton3 = aeCryptoCalc.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty,
"DES Encrypt"));
if (aeRadioButton3 == null)
throw new Exception("No RadioButton");
else
Console.WriteLine("Got RadioButton3");
Usan un modelo similar al que utiliza para obtener una referencia al control de botón. Sin embargo, observe que especificar TreeScope.Descendants en lugar de TreeScope.Children. Hacerlo porque el control RadioButton es que un secundario del control GroupBox y lo no es un secundario directo del control principal de Windows. Como alternativa, podría en primer lugar se ha obtenido una referencia al control GroupBox (como un elemento secundario del control principal de Windows) y, a continuación, utiliza esa referencia para obtener una referencia al control RadioButton. Una vez que tienen referencias a los controles, puede empezar a manipular la aplicación en el que se realiza la prueba. Comienzo mediante la simulación de entrada del usuario en el control TextBox1:
Console.WriteLine("\nSetting input to 'Hello1!'");
ValuePattern vpTextBox1 =
(ValuePattern)aeTextBox1.GetCurrentPattern(ValuePattern.Pattern);
vpTextBox1.SetValue("Hello!");
Mediante el método SetValue probablemente no se suministra como una sorpresa, pero observe obtener acceso que no a SetVaue() directamente mediante el aeTextBox1 objeto. En su lugar, utilizar un objeto de ValuePattern intermediario. El concepto de AutomationPattern objetos como ValuePattern es probablemente el mayor obstáculo conceptual para ingenieros de nuevo en la biblioteca Microsoft UI Automation. Se puede considerar de modelo de objetos como una abstracción para exponer funcionalidad de un control que es independiente de tipo o la apariencia del control. Dicho de otra forma, puede utilizar instancias AutomationPattern específicas como ValuePattern para habilitar la funcionalidad de control específico.
Simplifican aún más las cosas por pensar que ControlType de un control expone qué tipo de control es el control y que el modelo de un control expone lo que puede hacer el control. Utiliza un enfoque similar para simular un usuario selecciona el control RadioButton3:
Console.WriteLine("Selecting 'DES Encrypt' ");
SelectionItemPattern spSelectRadioButton3 =
(SelectionItemPattern)aeRadioButton3.GetCurrentPattern(
SelectionItemPattern.Pattern);
spSelectRadioButton3.Select();
Este tiempo utilice el SelectionItemPattern para habilitar una selección. A veces, el nombre del método GetCurrentPattern confuses MUIA biblioteca principiantes. Desde un punto de automatización de pruebas de vista, el método es configuración, no recibe un AutomationPattern especificado. Pero desde una perspectiva de cliente / servidor, el código de cliente de automatización es obtener una propiedad determinada de la aplicación en el código de servidor de prueba.
El código que usar para simular un clic en el control de botón calcular ayudarán a clarificar:
Console.WriteLine("\nClicking on Compute button");
InvokePattern ipClickButton1 =
(InvokePattern)aeButton.GetCurrentPattern(
InvokePattern.Pattern);
ipClickButton1.Invoke();
Thread.Sleep(1500);
Aquí, en esencia, utilizar el InvokePattern para habilitar un clic de botón y, a continuación, ejecutar hacer clic en mediante el método Invoke. Observe que Pausar 1,5 segundos para dar el tiempo de aplicación para responder. Puede también entran frecuentemente en un bucle de retraso, comprobar periódicamente si el campo de textBox2 resultados está vacío o no. En este momento en mi código de automatización de prueba, han inicia la aplicación en el que se realiza la prueba, escrito "Hello." en el entrada control de TextBox seleccionado el control RadioButton de cifrado DES y hacer clic en el control Button de cálculo.
Ahora examinar el control de TextBox2, para ver si han de un valor esperado correcto:
Console.WriteLine("\nChecking TextBox2 for '91-1E-84-41-67-4B-FF-8F'");
TextPattern tpTextBox2 =
(TextPattern)aeTextBox2.GetCurrentPattern(TextPattern.Pattern);
string result = tpTextBox2.DocumentRange.GetText(-1);
Aquí utilice TextPattern para preparar una llamada a un método GetText. Observe que se llama GetText indirectamente mediante una propiedad DocumentRange, que devuelve un intervalo de texto que rodea el texto principal de un documento, en este caso, un cuadro de texto. El argumento-1 GetText se utiliza para que no hay ningún límite máximo en la longitud de la cadena devuelta. Una manera alternativa para leer el contenido del control TextBox2, es utilizar el método GetCurrentPropertyValue:
string result =
(string)aeTextBox2.GetCurrentPropertyValue(ValuePattern.ValueProperty);
Tengo codificados en la entrada de caso de prueba en el instrumento de prueba. Un enfoque más flexible es leer la entrada de caso de prueba y los valores esperados de algunos almacén de datos externo. Ahora, con el valor real de la aplicación de prueba en mano, comprueba con un valor de esperado para determinar el resultado de aprobación o error de escenario de prueba:
if (result == "91-1E-84-41-67-4B-FF-8F") {
Console.WriteLine("Found it");
Console.WriteLine("\nTest scenario: Pass");
}
else {
Console.WriteLine("Did not find it");
Console.WriteLine("\nTest scenario: *FAIL*");
}
Simplemente se mostrar el resultado de escenario de prueba para el shell de comandos. En un entorno de producción, normalmente deseará escribir los resultados de las pruebas en almacenamiento externo.
Con mi escenario de prueba completado, puede cerrar la aplicación en el que se realiza la prueba por Ejercitar el control de menú. En primer lugar, aparece el control de MenuItem del archivo de nivel superior:
Console.WriteLine("\nClicking on File-Exit item in 5 seconds");
Thread.Sleep(5000);
AutomationElement aeFile = null;
aeFile = aeCryptoCalc.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty, "File"));
if (aeFile == null)
throw new Exception("Could not find File menu");
else
Console.WriteLine("Got File menu");
Observe que utilizan el ámbito TreeScope.Descendants ya que el control archivo MenuItem un subcontrol del control contenedor menú. Ahora simule que un usuario clic en el elemento de archivo:
Console.WriteLine("Clicking on 'File'");
ExpandCollapsePattern expClickFile =
(ExpandCollapsePattern)aeFile.GetCurrentPattern(ExpandCollapsePattern.Pattern);
expClickFile.Expand();
Controles de MenuItem que tienen submenús no exponen un modelo de Invoke como cabría esperar; expone un modelo de expandir. Con los elementos de submenú archivo ahora representados y visibles, puede obtener una referencia al comando Exit:
AutomationElement aeFileExit = null;
aeFileExit = aeCryptoCalc.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty, "Exit"));
if (aeFileExit == null)
throw new Exception("Could not find File-Exit");
else
Console.WriteLine("Got File-Exit");
Y ahora puede usar un InvokePattern en el submenú Salir para cerrar la aplicación CryptoCalc prueba:
InvokePattern ipFileExit =
(InvokePattern)aeFileExit.GetCurrentPattern(InvokePattern.Pattern);
ipFileExit.Invoke();
Console.WriteLine("\nEnd automation\n");
En este momento se realiza la automatización de prueba, y pueden registrar el resultado de caso de prueba e iniciar otro escenario de prueba.
Palabras finales
El código presentado en la columna de este mes le proporciona una buena base para la introducción a la creación de automatización de prueba personalizada para aplicaciones WPF. La biblioteca MUIA es bastante amplio y puede administrar la mayoría de los escenarios de pruebas sencillos.
El modelo para adaptar el sencillo ejemplo ha presentado aquí para probar su propia aplicación WPF es sencillo. Al crear la aplicación WPF, intente asegurarse de que todos los controles tienen un atributo de nombre de XAML para que se genera un AutomationID. Utilice la herramienta UISpy para determinar cómo identificar y manipular los controles de usuario. Determinar el modelo MUIA que permiten examinar el estado y el valor de un control de usuario. Con esta información en la mano, puede controlar escenarios de automatización de pruebas de interfaz de usuario más básicos.
En todos los casos pruebas, debe sopesar cuidadosamente el esfuerzo necesario para crear la automatización de prueba con la ventaja que obtiene de la automatización. Según mi experiencia, automatización de prueba de interfaz de usuario de WPF se suelen mejor utiliza para pruebas de regresión de escenarios relativamente sencillas. Esto permite concentrarse en el manual de las pruebas en escenarios complejos y encontrar errores nuevos, sutiles sin tener que preocuparse por falta de un error obvio que se presentó accidentalmente cuando desarrollo Agrega nueva funcionalidad.
Como general regla general, para el tipo de automatización de prueba ligero descrita en esta columna, he encontrado que si la automatización de prueba tarda menos de cuatro horas para crear, a continuación, obtener un valor razonable devuelto del valor de mi inversión de tiempo. Por supuesto su entorno será diferente; el punto es que debe no automáticamente asumir que automatización de prueba de interfaz de usuario es siempre el mejor uso posible de los recursos pruebas. WPF todavía es una tecnología relativamente nueva. Pero como la presencia de WPF aplicaciones aumenta, se pueda convertirse en cada vez más útil para crear software mejor las técnicas de automatización de interfaz de usuario prueba presentadas en esta columna.
Dr. James McCaffrey funciona para información biológicas volt, Inc., que administra el formación técnica para ingenieros de software trabaja en el campus de Redmond (Washington) de Microsoft. Ha trabajado en varios productos de Microsoft como Internet Explorer y MSN Search. Juan es el autor de .NET Test Automation Recipes (Apress, 2006). Juan puede ponerse en jmccaffrey@volt.com o v-jammc@microsoft.com.