Pruebas automáticas de la calculadora… o cualquier otra aplicación Windows

Tested calculator Siempre que en algún evento o en alguna formación muestro las pruebas web de Team System, surge una pregunta inevitablemente: ¿y esto no lo hay para aplicaciones Windows?… Mi respuesta tradicionalmente ha sido: No, no hay nada… y luego venía la explicación ‘oficial’ habitual: Es que tu aplicación debe tener una capa de interfaz muy fina y claro con las pruebas unitarias debería ser suficiente, no pasa nada porque algo de código de tu aplicación, relacionado con la interfaz de usuario se quede sin probar automáticamente, y bla, bla, bla…

El otro día uno de los desarrolladores de uno de los equipos para los que estoy haciendo mentoring sobre Scrum y Team System me decía lo siguiente: Según lo propugnado por las metodologías ágiles debemos probar todo lo que es susceptible de fallar y debemos automatizar toda prueba que sea automatizable, así que Rodrigo, tu respuesta no me deja contento… y la verdad es que tiene toda la razón. Si bien es cierto que existen herramientas de terceros que permiten grabar pruebas de interfaz de usuario estas son caras o muy caras, así que esta ocasión no nos sirven. Aquí termino la historia…

Es cierto que está respuesta cambiará notablemente con VSTS ‘Rosario’, que integrará de serie la posibilidad de grabar pruebas de interfaz de usuario, pero también es cierto que hasta Rosario nos queda un trecho.

Pero yo no me suelo rendir fácilmente, quien haya jugado conmigo a pelota mano lo sabe, y después de la conversación anterior he estado dándole vueltas al tema y tengo una nueva respuesta… no exenta de complejidades, pero una respuesta al fin y al cabo. La respuesta no pasa por grabar la pruebas al estilo de como se graban las pruebas web de VSTS, sino por escribir código que automatice las pruebas de interfaz de usuario.

Este enfoque es mucho más flexible que el grabar test, pues cuando nuestra interfaz de usuario sufre cambios en mi opinión es mucho más simple modificar código que grabar de nuevo los test. De hecho, los equipos que tienen baterías de pruebas web de tamaño considerable suelen elegir generar el código UI Automation Librariescorrespondiente a la prueba y modificarlo según su interfaz de usuario va cambiando. Aun recuerdo como en una visita a Redmond con ocasión de un MVP Summit, tuve gracias a Ricardo Varela, la posibilidad pasar un rato con un ingeniero de pruebas del equipo de Windows Mobile. Me enseño las pruebas automatizadas de interfaz de usuario que escribía ‘a manele’ y ejecutaba contra una ‘granja’ de diferentes modelos de PDA. Desde ese momento, tuve claro que automatizar pruebas de interfaz de usuario es posible y que escribir código para ello es un camino viable.

Con idea de saber si se puede andar este camino integrando nuestras pruebas con las pruebas unitarias de VSTS y para hacerme idea del la magnitud de esfuerzo que este camino exige he hecho un pequeño piloto. La idea es simple: automatizar el testeo de algunas acciones de la calculadora de Windows. La investigación previa me llevo a este artículo de MSDN Magazine: Test Run: The Microsoft UI Automation Library que me mostro el camino hacia la automatización de las pruebas de interfaz.

Así que vamos usar una útil y desconocida librería de Microsoft: UI Automation Library. Esta librería nos permite automatizar acciones sobre cualquier interfaz Windows sea está Win32, Windows Forms, Web o WPF y está orientada a soportar accesibilidad y las pruebas de interfaz de usuario. Para usarla será necesario añadir una referencia a UIAutomationClient y a UIAutomationTypes y hacer un ‘using’ de System.Windows.Automation. A partir de este momento tendremos acceso a las clases de la librería de automatización de la interfaz de usuario.

Usando esta librería es muy simple crear pruebas unitarias que automaticen nuestras pruebas de interfaz de usuario. Estas pruebas unitarias se pueden ejecutar desde VSTS sin problemas, pero no se podrán ejecutar como parte de una build de TFS, pues necesitan, lógicamente mostrar interfaz de usuario.

Os dejo el código de las pruebas hechas sobre la calculadora, creo que se explican por sí mismas. Son un ejemplo simple de como provocar acciones de interfaz de usuario usando UI Automation Library. También podéis descargar el código si lo deseáis.

using System.Diagnostics;

using System.Windows.Automation;

using Microsoft.VisualStudio.TestTools.UnitTesting;

 

namespace UITestingSample

{

  /// <summary>

 

  /// </summary>

  [TestClass]

  public class UITestSample

  {

    static AutomationElement _mainWindow;

 

    /// <summary>

    /// Initilizes objects needed for testing

    /// </summary>

    /// <param name=”testContext”>Test context</param>

    /// <remarks>

    /// Get the calculator’s main window automation element and store

    /// it in a static private field

    /// </remarks>

    [ClassInitialize()]

    public static void ClassInitialize(TestContext testContext)

    {

      Process[] processes = Process.GetProcessesByName(“calc”);

 

      if (processes.Length != 0)

      {

        _mainWindow =

          AutomationElement.FromHandle(processes[0].MainWindowHandle);

      }

      else

      {

        Assert.Inconclusive(“Windows Calculator must be running”);

      }

    }

 

    /// <summary>

    /// Test for sum

    /// </summary>

    [TestMethod]

    public void SumTest()

    {

      InvokeButton(“C”);

      InvokeButton(“1”);

      InvokeButton(“+”);

      InvokeButton(“1”);

      InvokeButton(“=”);

      Assert.AreEqual(GetDisplayText(), “2, “);

    }

 

 

    /// <summary>

    /// Test for square root

    /// </summary>

    [TestMethod]

    public void SqrtTest()

    {

      InvokeButton(“C”);

      InvokeButton(“9”);

      InvokeButton(“sqt”);

      Assert.AreEqual(GetDisplayText(), “3, “);

    }

 

    /// <summary>

    /// This function get the automation element corresponding to a button from its caption

    /// </summary>

    /// <param name=”caption”>Button’s caption</param>

    /// <returns>The automation element corresponding to the button</returns>

    private AutomationElement GetButtonByCaption(string caption)

    {

      return _mainWindow.FindFirst(

        TreeScope.Children,

        new PropertyCondition(AutomationElement.NameProperty, caption));

    }

 

    /// <summary>

    /// This function click a button provided its caption

    /// </summary>

    /// <param name=”caption”>Button’s caption</param>

    private void InvokeButton(string caption)

    {

      AutomationElement ae = GetButtonByCaption(caption);

      ((InvokePattern)(ae.GetCurrentPattern(InvokePattern.Pattern))).Invoke();

    }

 

    /// <summary>

    /// Get the text displayed by the calculator

    /// </summary>

    /// <returns></returns>

    private string GetDisplayText()

    {

      AutomationElement ae =

        _mainWindow.FindFirst(

          TreeScope.Children,

          new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));

 

      return (string)ae.GetCurrentPropertyValue(ValuePattern.ValueProperty);

    }

  }

}

La conclusión de mi pequeño piloto es que es plenamente posible escribir pruebas de interfaz de usuario e integrarlas dentro de las pruebas de usuario de VSTS. También es cierto que para que este esfuerzo sea viable, debemos poner mucho enfoque en crear una serie de funciones de ayuda que enmascaren el tener que lidiar con la UI Automation Library. La gran pregunta es ¿merece la pena el esfuerzo?… supongo que todo depende de la cantidad de código que tengamos en nuestra interfaz de usuario. Si logramos minimizar esta variable, como debemos perseguir en toda buena arquitectura, creo que el esfuerzo no merecerá la pena.

10 comentarios en “Pruebas automáticas de la calculadora… o cualquier otra aplicación Windows”

  1. Hola Rodrigo,

    ¡Excelente post! No sabes cuánto lo he disfrutado. Da gusto ver que la calidad del software es de importancia creciente y el uso de algunos frameworks de automatización ayudan mucho como bien has descrito.

    Estoy de acuerdo en todo lo que comentas, excepto en la última frase. Es correcto el criterio que planteas de separar totalmente lógica de UI en nuestros desarrollos. No obstante, hay casos en que la automatización de pruebas de UI es muy necesaria ante otro tipo de paradigmas. En el ejemplo que tú muestras, tienes más razón que un santo: interfaz estática, lógica separada… No obstante, ¿qué sucede ante otro tipo de paradigmas como por ejemplo el de una aplicación dirigida por los datos cuya UI está basada en un lenguaje de tipo declarativo (digamos XAML por ejemplo)? Esta cuestión quizá hoy nos resulte un tanto ajena pero se va a poner muy de actualidad en poco tiempo, teniendo en cuenta lo que se nos avecina. Comenzando por Oslo, también por el “mal” llamado lenguaje D. 🙂

    Tenía pensado retomar pronto la serie de posts sobre software testing que comencé hace mil años… Ahora con este post me has picado a hacerlo, y contestar esa pregunta tal vez sea un buen comienzo, quizá hasta ahora fui demasiado abstracto en esa serie de posts y debo centrarme en cuestiones más específicas. ¡Gracias! 🙂

    Un abrazo crack

  2. “Mi respuesta tradicionalmente ha sido: No, no hay nada… ”

    No hay nada de Microsoft, pero hay muchas aplicaciones en el mercado que llevan existiendo desde hace más de 10 años que son para este tipo de pruebas.

    “y luego venía la explicación ‘oficial’ habitual: Es que tu aplicación debe tener una capa de interfaz muy fina y claro con las pruebas unitarias debería ser suficiente, ”

    ¿El cómo? ¿Que tendrá que ver las pruebas unitarias con probar el interfaz de usuario? ¿Y por qué uno tiene que sustituir al otro? Son enfoques y pruebas completamente distintas. ¿Las pruebas unitarias van a probar que los tabuladores siguen una orden secuencial? ¿O es que es “no importa”?

  3. Aúpa Migue y Jose

    Yo no he hablado de que las pruebas unitarias sustituyan a las pruebas de intefaz, desde el punto de vista de pruebas de aceptación. Su propósito es radicalmente diferente.

    He hablado de que cuanto más finas es tu capa de interfaz, menos código tendrá, y menos se notará la carencia de pruebas automatizadas. Además ya he dicho que eso era, en cierto modo, la escusa oficial…

    En cuanto a que no hay herramientas, evidentemente hablo de herramientas de MS, pues ya he digo que hay muchas de otros fabricantes, a menudo demasiado caras para el equipo medio.

    Por último, decir que por mucho que automaticemos las pruebas de interfaz, nada sustituye a la labor de un tester en este aspecto. ¿Cómo desde una prueba automatizada detectas que los botones están mal alineados? ¿Cómo detectas una mala usabilidad? ¿Cómo detectas una intefaz que no se bien en ciertas configuraciones de pantalla? O por citar tu ejemplo ¿Cómo sabes con pruebas automatizadas que el ‘tab order’ es lógico y correcto?…

    Al fin y al cabo, como siempre he sostenido, lo mejor que podemos hacer por la calidad del software es poner un tester en nuestros proyectos (http://geeks.ms/blogs/rcorral/archive/2006/10/21/Pon-un-tester-en-tus-proyectos.aspx)

    Miguel, decirte que no veo la diferencia entre que la interfaz esté hecha en XAML/WPF o no… o que esté más o menos guiada por datos… es igualmente automatizable. Eso si, te doy la razón de que cuanto más cambie la interfaz de usuario en función de los datos, más necesarias y útiles serán las pruebas de automatización.

    Saludos y gracias por los comentarios.

  4. Rodrigo excelente referencia, y particularmente me gusta la forma en la que lo has presentado. Yo llegue a la UI Automation hace unos meses también a través de la MSDN Magazine y la verdad es que me dejó asombrado. Principalmente por la simplicidad con la que se pueden “detallas” las pruebas de UI más simples a traves de código.
    En otras palabras, el gran paradigma de las pruebas de UI, es poder expresar las mismas en un lenguaje específico y que luego el mismo se pueda automatizar en una o más pruebas.

    Saludos

  5. Hola de nuevo!

    Muy buen post y geniales comentarios, muy acertados a mi entender. 🙂

    Unas breves puntualizaciones:

    “cuanto más cambie la interfaz de usuario en función de los datos, más necesarias y útiles serán las pruebas de automatización.”

    Exacto Rodrigo, a eso me refería para justificar la importancia de este tipo de pruebas… En parte también porque he currado bastante en este tipo de pruebas y a uno no le gusta que digan que esa labor es prescindible, jejeje. 😛

    “Miguel, decirte que no veo la diferencia entre que la interfaz esté hecha en XAML/WPF o no… o que esté más o menos guiada por datos… es igualmente automatizable.”

    No me expliqué muy bien, pero piensa que WPF añade una serie de funcionalidades que si bien son puramente de UI y no de lógica, sí que tienen cierta lógica asociada (por ejemplo: animaciones de controles, animación de gráficas o de trazos simples, , etc). Imagina un grupo dedicado a la creación de frameworks de UI controls, el uso de este tipo de pruebas es imprescindible 🙂

    “Por último, decir que por mucho que automaticemos las pruebas de interfaz, nada sustituye a la labor de un tester en este aspecto.”

    Depende del nivel de madurez de pruebas en la empresa (TMMI), pero lo apropiado es que el desarrollador realice las pruebas unitarias sobre sus artefactos, y del resto de pruebas (incluídas las de UI) se encargue el tester. Es decir, este framework es para hacer un poco más sencilla la vida a los testers 🙂

    Un abrazo

  6. Hola Rodrigo,
    La verdad que hace unos días me he interesado por las pruebas de UI y he encontrado este proyecto que al igual os interesa, ya que reduce un poco la complejidad y en parte, las escusas para no realizar este tipo de pruebas 😉

    http://www.codeplex.com/white

    White provides consistent object oriented API for all kinds of applications. Also it hides all the complexity of Microsoft’s UIAutomation library and windows messages (on which it is based).

    Esta detrás una empresa conocida, Thoughtworks.

    Aún queda mucho por hacer ya que no es una versión del todo madura, pero os animo a participar 🙂

    Un Saludo

  7. Hola Rodrigo,
    Gracias por el post!! Solo una cosa, como dicen Thoughtworks esta detras del proyecto White, pero para entrar en detalle, detras de Thoughtworks esta Martin Fowler, que hace un tiempo escribio sobre el patrón de diseño Model View Presenter, que cubre esa necesidad junto con otros productos como RhinoMock. Lo he utilizado para pruebas del tipo “el usuario marca este radio button, y se bloquea el textbox X”. La diferencia que le veo es que con MVP estas obligado a hacer una interfaz – no es que este mal, sino que te obliga – para despues hacer la prueba. Por eso, mil gracias 🙂

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *