Windows Phone 7.5:Calidad del software, pruebas unitarias y ventas.

Hola a todos!

Hoy vamos a hablar un poco sobre las pruebas unitarias en Windows Phone 7.5. Es un tema del cual no existe mucha información ni guías sobre como llevarlas a cabo y que, extrañamente, se deja de lado normalmente. Como si no fuesen necesarias al tratarse de aplicaciones móviles.

Nada más lejos de la realidad. Creo que una de las frases que he escuchado últimamente que más sentido tiene es: “La calidad no es opcional”. En Plain Concepts esto es un mantra que nos repetimos constantemente.

Introducción

Todo proceso industrial moderno que tenga como objetivo colocar un producto en el mercado para su consumo, más o menos masivo, tiene un cierto nivel de calidad exigido. No quiero pensar que pasaría si cuando un fabricante de coches termina una unidad la pusiese directamente en el concesionario sin probarla en absoluto, o simplemente la arrancase para ver que el motor funciona con el acelerador y que el encendido / apagado no provoca una explosión. Todos sabemos que esto no es así. Los vehículos, juguetes, medicamentos, utensilios varios, etc… pasan un complicado entramado de pruebas internas y externas, certificaciones de seguridad y tienen un conjunto de regulaciones y certificaciones que cumplir. Gracias a esto, los coches no explotan.

Y ¿que pasa con el software? El software en el 90% de los casos sale a la venta sin una sola prueba… y cuando un usuario presiona “B” antes que “A” el PC explota por completo.

Esto se agrava más si cabe en el caso de las aplicaciones móviles. ¿Porque? ¿No se supone que son aplicaciones más sencillas y fáciles de desarrollar? El problema de las aplicaciones móviles no es tanto su tamaño o complejidad, es su ciclo de vida. Una aplicación móvil que puede ser consumida por millones de personas (por que si desarrollamos una aplicación móvil es para vender mucho ¿No?) en diferentes dispositivos, idiomas, redes de telefonía y condiciones de batería debe cumplir una premisa básica para tener éxito y mantenerlo: un ciclo de vida entre actualizaciones corto e incremental. Debemos actualizar nuestra aplicación de forma periódica, añadiendo características y corrigiendo bugs. Si tenemos éxito en las ventas empezaremos a tener competencia, que intentará desbancarnos ofreciendo más características, más eficiencia y menos fallos.

Es aquí cuando nos damos cuenta de que necesitamos de alguna forma controlar la calidad de nuestra aplicación. En un código tan expuesto a evolucionar y cambiar, un pequeño cambio en la clase CondensadorDeFluzo.cs puede provocar un error en la clase ViajeEnElTiempo.cs sin que seamos conscientes de ello. Hacemos dos o tres pruebas manuales sobre la funcionalidad nueva o cambiada y como todo va bien, enviamos a certificación, un proceso que puede tardar varios días. Cuando los usuarios se descargan nuestra aplicación, empezamos a recibir informes de fallos en la funcionalidad expuesta por ViajeEnElTiempo.cs, lo arreglamos, probamos y volvemos a repetir el proceso de certificación, vuelven a pasar los días. Seguimos recibiendo informes de error, en este caso en otra parte remota y olvidada de nuestro código, que no tocamos desde las primeras versiones, repetimos el mismo proceso, otra vez… lo que conocemos normalmente como Regresiones, que cualquiera acostumbrado a mantener un producto conocerá / sufrirá perfectamente.

Estamos en un circulo vicioso, cada vez cuesta más actualizar una funcionalidad sin que rompamos otra y los usuarios empiezan a percibir una constante: Nuestra aplicación es un asco porque con cada nueva versión se rompe algo. Con ello, empezamos a perder clientes y pronto, pasamos de estar ganando dinero a tener 0 descargas y 0 usuarios activos. ¿Ha fracasado nuestra aplicación? ¿O hemos fracasado en nuestro papel de fabricantes de un producto?. Sin duda, hemos fracasado en nuestro papel de fabricantes porque hemos descuidado la parte más importante del proceso: LA CALIDAD.

¿Qué podemos hacer? No existen balas de plata. Pero si pudiésemos de alguna forma implementar un sistema automático que se encargase de probar nuestro código bajo demanda. Al cual pudiésemos indicarle los parámetros para probar los métodos, que esperar y bajo que condiciones consideramos que nuestro código es funcional y correcto, evitaríamos escenarios como el expuesto más arriba y podríamos ampliar y corregir funcionalidades, asegurándonos que la aplicación sigue funcionando correctamente o encontrando los fallos de forma rápida antes de que lleguen al usuario. De hecho, ahora que lo pienso así… si que hay algo que hace esto: LAS PRUEBAS UNITARIAS.

Pruebas unitarias

Sobre las pruebas unitarias he oído de todo: que no sirven para nada, que son una perdida de tiempo, que como le vendes al cliente el tiempo que tardas en hacerlas… Todos somos mayorcitos, cada uno que desarrolle como quiera, pero plantearos esto: No puedes ir a un concesionario y pedir que te vendan un coche que no haya pasado las pruebas de seguridad y certificaciones elegidas por la ley, porque no hay de esos. Simplemente no existen y, es más, las compañías presumen de cuanto invierten en probar sus modelos. Sabes que una parte del precio que te cuesta, paga esas pruebas. Este es el truco: las compañías de coches NO GASTAN en pruebas, INVIERTEN en pruebas.

Así que, vamos a emular a la industria de la automoción, invirtiendo en dotar a nuestras aplicaciones de una calidad sobresaliente. Para ello vamos a desarrollar una aplicación Windows Phone 7.5. Es muy importante para poder realizar pruebas unitarias que usemos el patrón MVVM en nuestra aplicación. ¿No lo conoces? Mira estos artículos en mi blog que lo explican en detalle: aquí y aquí

Empezaremos con el diseño de la aplicación, muy sencilla. Esta aplicación nos permitirá escribir un nombre y pulsar un botón para que nos salude. Esta sería nuestra View:

    <StackPanel>
        <TextBlock Text="Enter your name:"
                    FontSize="{StaticResource PhoneFontSizeLarge}"
                    Margin="12,0,12,0">
        </TextBlock>
        <TextBox Text="{Binding Name, Mode=TwoWay}">
        </TextBox>
        <Button Content="Say Hello!"
                Command="{Binding HelloCommand}"
                CommandParameter="{Binding Name}">
        </Button>
    </StackPanel>

 

A continuación, necesitamos crear nuestra ViewModel, para ello, en vez de hacerlo en la misma aplicación Windows Phone, vamos a crear una nueva librería de clases de Windows Phone:

image

 

En este nuevo proyecto en primer lugar vamos a crear una clase llamada CommandHello que implementará la lógica de nuestro comando:

public class CommandHello : ICommand
{

    bool ICommand.CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    void ICommand.Execute(object parameter)
    {
        string name = parameter as string;

        MessageBox.Show(string.Format("Hello {0}", name));
    }
}

 

Es una clase muy sencilla, simplemente muestra un MessageBox usando para ello el parámetro que le ha sido indicado.

A continuación vamos a crear la ViewModel de nuestra View:

public class VMMainPage : INotifyPropertyChanged
{
    //Ctor
    public VMMainPage()
    {
        Name = "Yeray";
    }

    private string name;
    public string Name 
    {
        get { return name; }
        set 
        { 
            name = value;
            RaiseChange("Name");
        }
    }

    private ICommand helloCommand;
    public ICommand HelloCommand
    {
        get
        {
            if (helloCommand == null)
                helloCommand = new CommandHello();
            return helloCommand;
        }
    }

    //INotifyPropertyChanged Implementation

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaiseChange(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

 

Esta ViewModel es muy simple, implementa el interface INotifyPropertyChanged para poder notificar a la UI de cambios en las propiedades y expone dos propiedades: Name, donde contendremos el nombre indicado por el usuario y HelloCommand, una instancia de nuestro comando para ejecutar el código al presionar el botón.

Ahora ya hemos escrito código y podemos empezar a probarlo, antes incluso de enlazarlo con la interface de usuario. Necesitamos asegurarnos de que el código es funcional y se comporta como deseamos que lo haga.

Vamos a añadir un nuevo proyecto a la solución que tenemos creada, en este caso del tipo Test Project:

image

 

Lo primero que necesitamos hacer es añadir una referencia a nuestra librería de clases, donde se encuentra el código que hemos escrito. Hacemos click derecho sobre el proyecto de Test y seleccionamos la opción “Add reference” en la pestaña de proyectos seleccionamos “PhoneViewModels” y aceptamos.

En este paso observaremos algo extraño:

image

No tenemos que asustarnos, es simplemente un aviso de que el framework del proyecto de Test (.NET Framework 4) no coincide con el de PhoneViewModel (Silverlight 4). Solo tendremos que cerrar y volver a abrir la solución para que este aviso desaparezca. Aún así la referencia funcionará correctamente y sin darnos quebraderos de cabeza. Simplemente se trata de un aviso.

En este caso, como vamos a usar una clase que implementa el interface ICommand, debemos añadir una referencia al ensamblado System.Windows.dll, que podemos encontrar en:

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\Profile\WindowsPhone71

Para comenzar vamos a crear las pruebas para la clase CommandHello. Añadimos un nuevo test a nuestro proyecto de test, botón derecho sobre el proyecto PhoneTest y seleccionamos Add > New Test:

image

Seleccionamos la plantilla “Basic Unit Test” y establecemos como nombre: nombre de la clase a probar + Test, de esta forma podremos mantener una estructura similar al proyecto que estemos probando. Una vez creado, veremos el archivo de código de la clase CommandHelloTest:

[TestClass]
public class CommandHelloTest
{
    [TestMethod]
    public void TestMethod1()
    {
    }
}

Por defecto se crea un método “TestMethod1” que podemos (debemos) borrar. La única diferencia que veremos con otras clases es que la clase se encuentra decorada con el atributo “TestClass” que indica que contiene pruebas y los métodos se decoran con el atributo “TestMethod” para indicar que son pruebas.

Antes de continuar, añadimos a esta clase un using a PhoneViewModels, el namespace donde están nuestras ViewModels.

Ahora vamos a empezar a probar nuestra clase CommandHello, una de las primeras cosas que desearíamos probar es que el método CanExecute de CommandHello devuelve el valor adecuado. Por defecto solo podremos acceder a los métodos públicos de una clase, por lo que vamos a modificar la clase CommandHello para que sus métodos sean públicos:

public class CommandHello : ICommand
{
    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        string name = parameter as string;

        MessageBox.Show(string.Format("Hello {0}", name));
    }
}

 

De esta forma podremos acceder tanto al método CanExecute como al método Execute y probarlos, vamos a realizar una prueba unitaria (muy simple) para el método CanExecute:

[TestMethod]
public void CanExecuteTest()
{
    CommandHello target = new CommandHello();

    bool actual = target.CanExecute(null);

    Assert.IsTrue(actual);
}

 

Como podemos ver, nuestro método de prueba sigue la misma nomenclatura que nuestra clase: nombre del método + Test. Los nombres de todas las pruebas deben ser únicos, si quisiésemos realizar varias pruebas a un mismo método, probando distintas situaciones podríamos usar una nomenclatura: nombre del método _ Descripción de la prueba _ Test (por ejemplo: CanExecute_ReturnFalse_Test).

Ahora podemos comprobar si realmente funciona nuestro código de la forma que esperamos, devolviendo True cuando llamemos a CanExecute, para ello ejecutamos la prueba unitaria, podemos hacerlo pulsando con el botón derecho sobre el código y seleccionando la opción “Run Tests” lo que nos abrirá la pantalla de resultados de tests y ejecutará el test actual:

image

 

Esta pantalla nos indica que nuestro Test se ha pasado con éxito, es decir, nuestro código se comporta como esperamos en la prueba. si modificamos el test, por ejemplo para esperar que devuelva False:

[TestMethod]
public void CanExecuteReturnFalseTest()
{
    CommandHello target = new CommandHello();

    bool actual = target.CanExecute(false);

    Assert.IsFalse(actual);
}

 

El resultado al ejecutar el test será el siguiente:

image

Nuestro primer test ha funcionado, pero el nuevo que hemos escrito ha fallado, y nos indica que el fallo se debió a que el Assert.IsFalse no se cumplió. Con esto ya tendríamos una pista rápida de que nuestro código no se comporta como deseamos.

Estos test son muy simples, solo para que se entienda la mecánica con la que se pueden realizar tests en Windows Phone de la misma forma que en cualquier otro tipo de proyectos. Lo mejor de esta forma es que, si disponemos de un sistema de integración continua, estos test serán totalmente compatibles con el y podremos pasarlos de forma automatizada al realizar la integración de nuestro código.

A continuación os dejo el proyecto de ejemplo para que juguéis con el y os sirva de referencia.

 

Un saludo a todos y Happy Coding!!

Published 25/10/2011 18:56 por Josué Yeray Julián Ferreiro
Comparte este post:

Comentarios

# Community Day 2011 & Windows Phone Hack–a- Thon

Monday, November 14, 2011 6:52 AM por Josue Yeray

Hola a todos! Este fin de semana he tenido la suerte de estar en el Community Day, un evento de Microsoft

# Windows Phone 7 – Recomendación de enlaces interesantes (II)

Wednesday, January 18, 2012 10:07 AM por Jorge Serrano - MVP Visual Developer - Visual Basic

Vamos con una segunda retahíla de enlaces relacionados con Windows Phone 7.5 (Mango). En este caso y