Gestión de Software
Testing en eXtreme Programming
Gestión de Software 2006 Testing en eXtreme Programming
Grupo 6 Nombre Dayvis Malfará Diego Cukerman Fernando Cócaro Juan uan Pabl Pabloo Cass Cassin inel ellili Renzo Sé Séttimo
Cédula 3860676-3 3348340-9 4347371-1 3100053-8 3-8 2766129-5
Página 1 de 19
Gestión de Software
Testing en eXtreme Programming
Página 2 de 19
Gestión de Software
Testing en eXtreme Programming
Este informe tiene como objetivo investigar los métodos y prácticas empleadas por la metodología de desarrollo de software eXtreme Programming (Programación Extrema) para realizar el testing de los productos que se construyen al emplear la misma. Cabe destacar que este documento esta orientado a personas con conocimientos previos en Extreme Programming.
Página 3 de 19
Gestión de Software
Testing en eXtreme Programming
En este capítulo daremos una pequeña introducción a eXtreme Programming, sin pretender abarcar demasiado en esta metodología.
eXtreme Programming de ahora en adelante XP, es una metodología de desarrollo de software ágil, que considera a las personas como un factor decisivo para lograr el éxito de un proyecto. Por ser un proceso ágil tiene como principal característica su adaptación a entornos cambiantes. Esto es posible porque el proceso esta diseñado para adaptarse en forma inmediata a los cambios, con bajos costos asociados en cualquier etapa del ciclo de vida. “XP es una metodología ágil para pequeños o medianos equipos, desarrollando software cuando los requerimientos son ambiguos o rápidamente cambiantes.” [Beck, 2000]
Esta diseñada para trabajar en pequeños o medianos equipos de hasta 12 integrantes. Esto fomenta la comunicación e interacción entre sus integrantes, logrando el trabajo en equipo. De esta forma, es posible reducir el costo de transferir información entre los mismos, al tener a todo el equipo compartiendo un mismo lugar de trabajo. El cliente cumple un rol fundamental en XP, dirigiendo el proyecto a lo largo del mismo. Este es quién fija las prioridades, y los programadores desarrollan lo que es necesario para ese momento en particular. En pequeñas iteraciones el sistema va creciendo según los requerimientos solicitados por el cliente, él cual puede observar el avance del proyecto en todo momento.
Kent Beck enuncia doce prácticas que sirven como un punto de partida para un equipo XP, las cuales se basan en los valores de simplicidad, comunicación, retroalimentación y coraje. Podemos plantear estas prácticas en tres capas:
Programación: Diseño Simple, Refactoring, Estándares de código, Pruebas.
Prácticas del equipo: Pequeñas entregas, Metáfora, Programación por pares, Propiedad colectiva, Integración continua, 40 horas semanales.
Los procesos: Cliente on-site El juego de la planificación, Pruebas, Pequeñas entregas. ,
Como podemos observar hay prácticas que se repiten en las diferentes capas, ya que están relacionadas en cada una de ellas. A continuación se presenta un detalle de cada práctica: •
•
El juego de la planificación Mediante esta práctica se realiza la planificación del proyecto en XP. La misma consiste en el plan de entregas, el plan de iteraciones, las historias de usuario, las tareas y los casos de pruebas para las mismas. Pequeñas entregas Las entregas deben ser lo más pequeñas posibles, conteniendo siempre los requerimientos del negocio mas importantes para el cliente en ese momento dado. De esta manera el cliente va obteniendo funcionalidades del sistema en forma gradual hasta finalizar el proyecto. En cada entrega los programadores obtienen retroalimentación del cliente determinando si lo implementado es lo que en realidad necesita. Página 4 de 19
Gestión de Software •
•
•
•
Testing en eXtreme Programming
Metáfora La metáfora le brinda al equipo una imagen del sistema la cual ellos pueden utilizar para describir la estructura en forma simple y sencilla. Las ventajas de su aplicación es que hace más fácil la comprensión del sistema y colabora para mantener un diseño simple. Diseño simple El diseño se va creando en forma progresiva, sin prever las necesidades del futuro. Al tener un diseño simple capaz de mantener las características actuales del sistema, este puede adaptarse mejor a un entorno cambiante cuando surgen nuevos requerimientos o cambian los actuales. Pruebas Las pruebas (testing) son una de las prácticas fundamentales en las cuales se basa XP. Esta actividad se realiza en forma continua a lo largo del proyecto. Existen dos tipos de pruebas, las unitarias y las de aceptación. Las pruebas unitarias son definidas por los programadores antes de comenzar a escribir código. Éstas deben contemplar cada módulo del sistema que pueda generar fallas. Para poder integrar el código realizado al ya existente, el mismo debe aprobar satisfactoriamente todos los casos de prueba definidos. El cliente con ayuda del tester define las pruebas de aceptación para cada historia de usuario a principio de cada iteración. Las pruebas de aceptación se utilizan para validar que cada requerimiento implementado funciona como se había especificado. Refactoring
Significa mejorar el diseño del código sin cambiar la funcionalidad actual. Aplicar esta técnica permite reducir la complejidad del código y eliminar posibles redundancias.
•
•
•
•
Programación por pares Todo el código producido en XP es realizado en parejas, dos personas frente a una computadora. Los roles en la pareja son de “conductor” y “acompañante”. El “conductor” es el que maneja el teclado y el ratón (mouse), pensando la mejor manera de cómo implementar el código. El “acompañante” tiene como tarea observar y corregir los errores cometidos por el “conductor”, considerar soluciones alternativas y sugerir nuevos casos de prueba. Esta constante revisión produce código y un diseño con mayor calidad. Periódicamente se debe intercambiar los roles de la pareja. De esta forma, se asegura transmitir el conocimiento del sistema a todo el equipo y eliminar las dependencias de personas que conocen partes del sistema. Propiedad colectiva Esta práctica se basa en que todo el código desarrollado pertenece al equipo. Todos los integrantes del equipo tienen la misma responsabilidad sobre todo el sistema. Al ser el equipo el responsable, cualquier integrante esta autorizado a realizar los cambios que se consideren necesarios para mejorar la calidad del mismo. De esta manera se logra descentralizar el conocimiento y no generar dependencias hacia las personas. Integración continua La integración de código se debe realizar en forma continua, esto implica al menos en un lapso de un día de trabajo y de ser posible cada unas pocas horas. La ventaja de la integración continua es obtener retroalimentación lo más rápido posible. Además de ser más sencilla que las integraciones que se realizan luego de varias semanas de programación. 40 horas semanales Esta práctica expone que 40 es la cantidad de horas que se debe dedicar al trabajo semanalmente. De esta manera se logra cometer menos errores por cansancio y aumentar la productividad del equipo. Página 5 de 19
Gestión de Software •
•
Testing en eXtreme Programming
Cliente on-site Para lograr un correcto funcionamiento de un proyecto en XP es necesario contar con la presencia full-time del cliente en el lugar de trabajo, siendo éste un integrante más del equipo. Contar con un cliente en el lugar de trabajo fomenta la comunicación y reduce la posibilidad de malentendidos y tiempos de espera. Estándares de código El equipo de programadores define en forma consensuada los estándares de programación que utilizará. De esta manera se logra obtener un código uniforme, como si el sistema fuera programado por una sola persona. Esta práctica fomenta la comunicación y facilita la implementación de las prácticas de refactoring, programación en pareja y propiedad colectiva.
Página 6 de 19
Gestión de Software
Testing en eXtreme Programming
En este capítulo presentaremos el testing en XP, explicando diferentes puntos acerca de su metodología. Explicaremos el rol del tester, la práctica programación por pares y todo lo referente a las pruebas, tanto unitarias como de aceptación.
El tester es el responsable de ayudar al cliente a seleccionar y escribir las pruebas de aceptación para cada historia de usuario. Tiene la responsabilidad de ayudar al cliente a tomar las decisiones correctas sobre que significa la calidad para su proyecto. El tester se encarga de ayudar al cliente a definir los criterios de calidad para cada historia de usuario. Estos criterios son necesarios para los programadores a la hora de estimar la duración de cada historia. Cuanto más precisos sean los criterios más exactas serán las estimaciones [Crispin.2001] Según Lisa Crispin y Tip House [CRISPIN, HOUSE. 2002] el testing es la única disciplina que requiere experiencia y entrenamiento, además de habilidad para resolver problemas. También involucra tener tacto y destreza en la comunicación para generar una relación productiva con clientes y programadores. El tester escribe las pruebas de aceptación, pero NO debe escribir las pruebas unitarias, esto lo debe hacer cada desarrollador empleando herramientas para su automatización. Luego de ejecutar las pruebas de aceptación el tester debe exponer los resultados obtenidos, en un lugar al cual todos los integrantes del equipo puedan acceder, para informar los defectos encontrados. Esto permite tener una clara visión del avance del proyecto.
Página 7 de 19
Gestión de Software
Testing en eXtreme Programming
Todo el código producido en XP es realizado en parejas, dos personas frente a una computadora. Los roles en la pareja son de “conductor” y “acompañante”. El “conductor” es el que maneja el teclado y el ratón (mouse), pensando la mejor manera de cómo implementar el código. El “acompañante” tiene como tarea observar y corregir en todo momento, los errores cometidos por el “conductor”, considerar soluciones alternativas y sugerir nuevos casos de prueba. Esta constante revisión produce código y un diseño con mayor calidad. El código producido debe cumplir con todos los estándares de programación permitiendo el entendimiento de este por todos los programadores y acompañantes, nunca debe haber mas de dos integrantes al mismo tiempo. Periódicamente se debe intercambiar los roles de la pareja. De esta forma, se asegura transmitir el conocimiento del sistema a todo el equipo y eliminar las dependencias de personas que conocen partes del sistema. La programación en pareja tiene muchas ventajas. La constante revisión del código, ya que existe una persona observando todo lo que haga la otra programa. El alternar de los integrantes de las parejas frecuentemente lo cual lleva a que todos tienen un conocimiento general del sistema, eliminando las dependencias hacia personas que conocen partes especificas del código. Por otro lado permite que los programadores con diferente experiencia puedan trabajar juntos, beneficiando a los más inexpertos que programan aprendiendo de los más expedientes. A su vez existe una práctica llamada Propiedad colectiva que se basa en que todo el código desarrollado pertenece al equipo, todos los integrantes del equipo tienen la misma responsabilidad sobre todo el sistema. Al ser el equipo el responsable, cualquier integrante esta autorizado a realizar los cambios que se consideren necesarios para mejorar la calidad del mismo. De esta manera se logra descentralizar aun más el conocimiento y no generar dependencias hacia las personas. Todo esto lleva a una constante verificación del código mientras este se esta generando, reduciendo considerablemente de esta manera la probabilidad de faltas en el sistema, por lo tanto la disminución de fallas en el mismo, por otro lado lleva a generar un código claro y entendible por todos los programadores, con algoritmos y casos de pruebas bien elaborados y revisados, mejorando así la calidad del producto.
Una prueba unitaria es la verificación de un módulo (unidad de código) determinado dentro de un sistema. El concepto de “módulo” varía de acuerdo al lenguaje de programación que estemos utilizando; por ejemplo, en Java sería una clase. Las pruebas unitarias nos aseguran que un determinado módulo cumpla con un comportamiento esperado en forma aislada antes de ser integrado al sistema. Los programadores realizan estas pruebas cuando: la interfaz de un método no es clara, la implementación es complicada, para testear entradas y condiciones inusuales, luego de modificar algo. Éstas deben contemplar cada módulo del sistema que pueda generar fallas. Para poder integrar el código realizado al ya existente, el mismo debe aprobar satisfactoriamente todos los casos de prueba definidos. En XP los programadores deben escribir las pruebas unitarias para cada módulo antes de escribir el código. No es necesario escribir casos de prueba para todos los módulos, sólo para aquellos en que exista la posibilidad de que puedan fallar. Luego de escribir el código, los programadores ejecutan las pruebas, las cuales deben resultar 100% efectivas para que el código pueda integrarse al sistema. En caso contrario hay que solucionar los errores y ejecutar nuevamente los casos de prueba hasta lograr que ninguno de ellos. Las pruebas son automatizadas utilizando herramientas como xUnit, de forma tal de poder soportar un testing continuo y mantener organizados los casos de pruebas. Página 8 de 19
Gestión de Software
Testing en eXtreme Programming
La ausencia de las pruebas unitarias lleva a tener que invertir una gran cantidad de horas en sesiones de debugging al momento de integrar el código con el sistema existente. Las pruebas unitarias brindan una inmediata retroalimentación el la realización de su trabajo, permiten al programador saber si una determinada funcionalidad se puede agregar al sistema existente sin alterar el funcionamiento actual del mismo. También permiten la aplicación de otras prácticas como refactoring y diseño simple al estar respaldados por efectivos casos de prueba. La retroalimentación que se genera por la realización de las pruebas, deriva en un constante aprendizaje sobre el sistema a realizar, lo cual permite que los programadores desarrollen de forma más rápida y eficiente.
En los últimos años se han creado una serie de frameworks que permiten automatizar las pruebas unitarias, permitido definir estas y ejecutarlas en reiteradas ocasiones. Estos frameworks son denominados xUnit. Estos framewors se basan en los conceptos de Test Case y Test Suite, el primer es la prueba unitaria del componente a testear, la segunda nos permite agrupar varias pruebas unitarias para poder ejecutarlas en forma conjuntas. La finalidad de los Test Case es probar funcionalidad de un determinado modulo. En lenguajes orientados a objetos seria probar los métodos de una clase. Los Test Suite permiten agrupar todas las pruebas de un componente, permitiendo ejecutar de forma conjunta todas las pruebas definidas para un Componente. A medida que el desarrolló va avanzando y se van definiendo mas caso de pruebas, estas herramientas nos permiten hacer pruebas de regresión. De esta forma si hay cambios en clases ya testeadas se les puede volver a evaluar su correctitud. Esto es muy útil en el caso de XP donde cuando hay cambios se evalúan y hace una refactorizacion para mantener de forma simple el producto, estas herramientas nos permiten poder reevaluar que tras los cambios se sigan cumpliendo las pruebas anteriormente definidas. Las principales ventajas de la utilización de pruebas unitarias automáticas en el desarrollo son: 1. : Las pruebas unitarias facilitan que el programador cambie el código para mejorar su estructura (lo que se ha dado en llamar refactorización), puesto que permiten hacer pruebas sobre los cambios y así asegurarse de que los nuevos cambios no han introducido errores. 2. : Puesto que permiten llegar a la fase de integración con un grado alto de seguridad de que el código está funcionando correctamente. De esta manera se facilitan las pruebas de integración. 3. : Las propias pruebas son documentación del código puesto que ahí se puede ver cómo utilizarlo. 4. : dado que tenemos pruebas unitarias que pueden desenmascararlos.
JUnit es la framework xUnit para la plataforma Java, esta nos permite definir los casos de prueba unitarios para las clases importantes del sistema. Permite ejecuta las clase de forma controlada para poder evaluar si esta se comporta de la manera esperada. JUnit ejecutara las pruebas sobra la clase y comparara contra los resultados esperados, si los resultados son correctos indicara que las pruebas fueron exitosas, en caso que alguno de los resultados no sea el esperado Junit indicara que se produjo un fallo he indicara el o los métodos que no pasaron sus evaluaciones. Es importante destacar que Junit seguirá con las pruebas aunque ya se haya detectado una falla. Página 9 de 19
Gestión de Software
Testing en eXtreme Programming
Este framework es Open Source y fue desarrollado por Kent Beck y Erich Gamma, el primero uno de los creadores de XP y el segundo conocido por ser uno de los lideres del proyecto Eclipse y por sus trabajos en Patrones de Diseño. En JUnit, los casos de prueba son clases que derivan de la clase TestCase, e implementan métodos sin parámetros de nombre testXXX, donde XXX es una descripción de lo que está probando ese método (Beck y Gamma, n.f.). Las pruebas implementadas que extenderán de la clase TestCase tiene la posibilidad de sobreescribir los métodos setUp() y tearDown(), los cuales son invocados antes y después de cada método de test. Esto permite inicializar y liberar recursos entre la ejecución de los distintos métodos en la clase, permitiendo asegurarse de que no hay efectos colaterales entre la ejecución de los distintos test. El propio framework incluye formas de ver los resultados (runners) que pueden ser en modo texto, gráfico (AWT o Swing) o como tarea en Ant. En la actualidad las herramientas de desarrollo como NetBeans y Eclipse cuentan con plug-ins que permiten que la generación de las plantillas necesarias para la creación de las pruebas de una clase Java se realice de manera automática, facilitando al programador enfocarse en la prueba y el resultado esperado, y dejando a la herramienta la creación de las clases que permiten coordinar las pruebas. Los TestCase pueden unirse en árboles de TestSuite que invocan automáticamente todos los métodos testXXX() definidos en cada TestCase. Un TestSuite es una composición de otros tests, bien TestCase u otros TestSuite. El comportamiento compuesto exhibido por los TestSuite te permite ensamblar suites de tests, de una profundidad arbitraria, y ejecutar todos los tests automáticamente para obtener un simple estado de pasado o fallado. Los métodos de prueba consisten en verificar que los resultados obtenidos sean los esperados. Para esto JUnit ofrece un conjunto de métodos (assert, assertEquals, assertTrue y otros) que permiten realizar comparaciones entre objetos o comprobar la veracidad de una condición determinada. Para realizar un caso de test en Junit se deben seguir los siguientes pasos. Escribir un test para probar un único componente de software. Enfocándose en escribir test que comprueben el comportamiento que tiene el mayor potencial de rotura, así puede maximizar los beneficios con respecto a la inversión en testeo. Para escribir un test, sigue estos pasos: 1. Define una subclase de TestCase. 2. Sobrescribe el método setUp() para inicializar el objeto(s) a probar. 3. Sobrescribe el método tearDown() para liberar el objeto(s) a probar. 4. Define uno o más métodos testXXX() públicos que prueben el objeto(s) y aserten los resultados esperados. 5. Define un método factoría suite() estático que cree un TestSuite que contenga todos los métodos testXXX() del TestCase. 6. Opcionalmente, define un método main() que ejecute el TestCase en modo por lotes. Supongamos que tenemos la siguiente clase Money (moneda) con sus correspondientes métodos y propiedades: class Money { private int fAmount; private String fCurrency;
Página 10 de 19
Gestión de Software
Testing en eXtreme Programming public Money(int amount, String currency) { fAmount= amount; fCurrency= currency; } public int amount() { return fAmount; } public String currency() { return fCurrency; } public Money add(Money m) { return new Money(amount()+m.amount(), currency()); } public boolean equals(Object anObject) { if (! anObject instanceof Money) return false; Money aMoney= (Money)anObject; return aMoney.currency().equals(currency()) && amount() == aMoney.amount(); }
}
La siguiente tabla muestra una breve descripción de los métodos de la clase: Método
Descripción
public Money(int amount, String currency) public Money add(Money m)
Constructor de la clase Money. Devuelve un objeto Money resultante de la suma de los dos montos. Indica si dos objetos Money son iguales, comparando sus propiedades (Currency y Value).
public boolean equals(Object anObject)
Los pasos a seguir, para construir un caso de prueba para la clase Money, son los siguientes: 1. Definir la clase de prueba que derive de la clase TestCase. import junit.framework.TestCase; import junit.framework.TestSuite; import junit.framework.Test; public class MoneyTest extends TestCase { //… private Money mobj12USD; private Money mobjf14USD; //… }
2. Sobreescribir el método setUp() para inicializar el/los objetos implicados en la prueba (si es necesario). protected void setUp() { mobj12USD = new Money(12, "USD"); mobjf14USD = new Money(14, "USD"); }
Página 11 de 19
Gestión de Software
Testing en eXtreme Programming
3. Sobreescribir el método tearDown() para liberar el/los objetos implicados en la prueba (si es necesario). 4. Definir uno o más métodos con signatura testXXX() que prueban las diferentes funcionalidades y casos de la clase. public void testAdd() { Money expected = new Money(26, "USD"); Money result = mobj12USD.add(mobjf14USD); assert(expected.equals(result)); } public void testEquals() { assert(!mobj12USD.equals(null)); assert(mobj12USD, mobj12USD); assertEquals(mobj12USD, new Money(12, "USD")); // (1) assert(!mobj12USD.equals(mobjf14USD)); }
5. De ser necesario, definir un método de clase suite() que crea una TestSuite a la que se añaden todos los métodos testXXX() del TestCase. public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest(new MoneyTest("testEquals")); suite.addTest(new MoneyTest("testAdd")); return suite; }
6. Definir un método main() que ejecuta el TestCase (o invocar el Test Runner en modo gráfico y especificar el caso de prueba o la suite). public static void main(String args[]) { test.textui.TestRunner.run(suite()); }
La interfaz de usuario en modo gráfico presenta una barra de progreso la cual toma color verde si todas las pruebas ejecutadas son 100% satisfactorias, o color rojo si falló alguna. En este último caso se despliega en una lista la descripción de las fallas o errores generados.
La automatización de las pruebas unitarias permite al programador ejecutar todas las pruebas cuantas veces sea necesario, logrando así determinar en forma inmediata si el cambio realizado a un módulo del sistema se puede integrar al mismo sin alterar el funcionamiento actual. Página 12 de 19
Gestión de Software
Testing en eXtreme Programming
Las pruebas de aceptación son pruebas de caja negra definidas por el cliente para cada historia de usuario, y tienen como objetivo asegurar que las funcionalidades del sistema cumplen con lo que se espera de ellas. En efecto, las pruebas de aceptación corresponden a una especie de documento de requerimientos en XP, ya que marcan el camino a seguir en cada iteración, indicándole al equipo de desarrollo hacia donde tiene que ir y en qué puntos o funcionalidades debe poner el mayor esfuerzo y atención. “Las pruebas de aceptación permiten al cliente saber cuando el sistema funciona, y que los programadores conozcan que es lo que resta por hacer.” (Jeffries et al. 2000, 45) Las pruebas de aceptación tienen una importancia crítica para el éxito de una iteración. Por lo tanto el tester debe tenerlas prontas lo antes posible a partir del comienzo de la iteración, y lograr que el cliente las apruebe para poder presentárselas cuanto antes al equipo de desarrollo.
En XP las pruebas de aceptación son en última instancia responsabilidad del cliente ya que deben reflejar los requerimientos y las funcionalidades que se quieren obtener en cada iteración. Es más, en algunos proyectos realizados con la metodología XP, el cliente llega a escribir las pruebas de aceptación. Sin embargo la mayoría de los clientes, especialmente cuando son externos al proyecto, son personas muy ocupadas con trabajos de tiempo completo, por lo tanto no disponen de demasiado tiempo para dedicarle al proyecto. Además generalmente no tienen ni la experiencia ni los conocimientos técnicos necesarios para escribir correctamente las pruebas de aceptación. Por esta razón el tester debe reunirse con el cliente para interpretar sus ideas y sus necesidades y luego poder escribir los casos de prueba correspondientes. También es importante que el tester guíe al cliente en la definición de los criterios de calidad, realizando diferentes cuestionarios e identificando lo que es crucial para el. Es importante también que el cliente especifique criterios de estabilidad y performance si los mismos son relevantes para la iteración. Por ejemplo, si un sistema tiene que manejar un gran número e usuarios o transacciones a una velocidad determinada, el grupo de desarrollo debe aumentar las horas estimadas para contemplar estas características. En muchos casos, la estabilidad y la performance del sistema se convierten en historias de usuario independientes. Por otra parte, es responsabilidad del cliente brindar los datos para poder ejecutar las pruebas de aceptación. Estos datos podrían ser creados o generados específicamente para las pruebas, pero generalmente los clientes ya cuentan con archivos o datos reales que pueden poner a disposición del equipo de desarrollo. Esto permite que estas pruebas sean lo más parecidas posible al ambiente de producción en donde se va a utilizar el sistema, logrando así una disminución importante de las fallas detectadas luego de la implantación del mismo. Según Crispin y Tip House (2002) los datos de prueba son tan importantes como las pruebas en sí mismas. La mayoría de los clientes no tienen claro en una primera instancia todas las características de cada historia de usuario. Muchas veces asumen que los programadores conocen todas sus necesidades, lo que provoca decepción en el momento en el cual el cliente recibe las funcionalidades implementadas durante la iteración. Es por esto que el tester debe interactuar con el cliente de manera de no dejar ningún detalle sin especificar dentro de las pruebas de aceptación. Crispin (2001) propone la revisión de las pruebas de aceptación junto con los programadores, ya que muchas veces existen pruebas unitarias que se superponen con alguna prueba de aceptación propuesta por el cliente. Es más, en ocasiones los programadores sugieren que determinadas pruebas de aceptación se realicen como pruebas unitarias, logrando así optimizar el esfuerzo.
Página 13 de 19
Gestión de Software
Testing en eXtreme Programming
En XP las pruebas de aceptación cumplen con el objetivo de indicarnos cuando las funcionalidades de una iteración han sido completadas exitosamente. A diferencia de las pruebas unitarias, el criterio de aprobación de las pruebas de aceptación no tiene que se necesariamente de 100% de efectividad. Todos sabemos que es imposible esperar un código totalmente libre de errores, por lo tanto es necesario definir un criterio de aprobación para saber cuando el software está listo para ser liberado. El cliente podría demandar que el 100% de los casos de prueba sean exitosos para pasar de iteración. Sin embargo como en XP las iteraciones tienen que terminar en fecha y los tiempos límites de entrega no son negociables, esto provocaría un tiempo de estimación mayor para cada historia de usuario. Por lo tanto, generalmente se sugiere que el cliente incluya pruebas de aceptación no críticas. Si estas pruebas se superan exitosamente generan una cuota extra de confianza en el cliente, pero si las mismas fallan en el fin de una iteración el cliente puede decidir repetir dichas pruebas al final de la siguiente iteración aumentando el grado de criticidad de las mismas.
Una vez que se comprendieron los requerimientos del cliente para las pruebas de aceptación estamos en condiciones de comenzar a definir los casos de pruebas. Cabe recordar que el objetivo de estas pruebas no es tener un conjunto de casos escritos que cubran el 100% del código, sino poder realizar el testing del sistema desde el punto de vista del usuario. En XP se considera que las pruebas de aceptación deben consistir en un conjunto mínimo (no pobre ni insuficiente) de casos que cubran los requerimientos de negocios fundamentales planteados por el cliente. Para escribir los casos de prueba se deben tener en cuenta ciertas consideraciones importantes. En primer lugar cada caso debe servir para obtener un feedback rápido y concreto de cómo se está desarrollando la iteración y el proyecto. Se tienen que tratar de evitar los casos de pruebas extensos que incluyan un gran número de pasos. Los casos escritos deben ser concisos y hay que documentar por separado los pasos del caso y los datos de prueba en sí mismos. Es importante señalar también que todos los casos de prueba cumplidos con éxito en iteraciones anteriores se deben seguir cumpliendo en todas las iteraciones, y si se produce un error aunque sea en un único paso del caso de prueba se considera que todo el caso falló. A continuación presentamos un ejemplo de un caso de prueba de aceptación tomado de Crispin (2001). En la figura 1 se muestra el resumen del caso, en la figura 2 se detallan los pasos del caso y las acciones que se deben llevar a cado, y en la figura 3 se especifican los datos de las diferentes pruebas realizadas.
Página 14 de 19
Gestión de Software
Testing en eXtreme Programming
Por último cabe mencionar que XP recomienda la automatización de los casos de pruebas de aceptación para permitir que sean ejecutados por lo programadores ni bien tengan una porción del código más o menos terminada. De todas formas esto depende de cada caso y del tipo de proyecto, ya que algunas veces el costo de automatizar los casos de prueba y luego mantenerlos es muy alto y por lo tanto se opta por la ejecución manual de los mismos. Es muy común que los casos de pruebas de una iteración no se puedan automatizar en esa misma iteración por problemas de tiempo, pero a veces esta tarea se puede realizar en iteraciones siguientes ya que estos casos se van a correr en todas las sucesivas iteraciones.
Otra importante diferencia entre las pruebas de aceptación y las pruebas unitarias es que para las de aceptación la presentación de lo resultados es importante, en cambio para las unitarias no tiene mucho sentido ya que siempre se requiere un 100% de efectividad. Beck (2000) recomienda la exhibición de los resultados que se obtienen al ejecutar las pruebas de aceptación, generando reportes y gráficas que desplieguen los porcentajes de efectividad obtenidos. Estos índices permiten evaluar si el equipo de desarrollo esta realizando un buen trabajo o no. Es importante mantener esta información estadística actualizada y visible para todos los integrantes del proyecto. Crispin (2001) propone el siguiente cuadro de resumen donde presenta tanto gráfica como numéricamente los casos de pruebas escritos, ejecutados y exitosos.
Página 15 de 19
Gestión de Software
Testing en eXtreme Programming
Otro ejemplo presentado en Jeffries 1999 intenta mostrar la cantidad de casos de pruebas de aceptación ejecutados en cada iteración, diferenciándolos entre los casos exitosos, los casos que fallaron y los que no fueron validados por el cliente.
En la figura 5 podemos observar que hay una clara tendencia que indica que en cada iteración se incrementen los casos escritos y ejecutados con respecto a la anterior. Además para que el proyecto culmine de forma exitosa es necesario que en las iteraciones finales los casos con error y los no validados por el cliente disminuyan, llegando a la última iteración con el 100% de los casos validados.
En esta sección se da una opinión personal referente al desarrollo y testing en XP, basado en la experiencia adquirida en el curso de ingeniería de software en el año 2003. En ese año se ponía en práctica esta metodología de desarrollo a modo de evaluación, la idea era ver la factibilidad de incorporar dicha metodología a las ya existentes en el curso (RUP y ModsGx). Por lo visto no resultó muy satisfactoria dicha metodología, ya que no se ha vuelto a aplicar, en un Página 16 de 19
Gestión de Software
Testing en eXtreme Programming
principio porque el coach se ve sobrecargado al momento de dirigir los grupos, ya que los grupos saben muy poco (o nada) de la metodología y todo es nuevo para los estudiantes. Dos de los actuales integrantes de este grupo fuimos partícipes de dicha experiencia, asumiendo los roles de Analista – Desarrollador y Verificador – Desarrollador. Los grupos que aplicaron esta metodología estaban compuestos por siete integrantes, se desarrollaba sobre GeneXus + WorkFlow utilizando para ello el generador java desarrollando para Web. Ambos grupos que aplicaron GXP (GeneXus Extreme Programming) tenáin un cliente común, el SECIU, a manos de la Ing. Mariela de Leon. El proyecto a desarrollar fue un prototipo de factibilidad referente al manejo y seguimiento de expedientes tanto electrónicos como en papel para la Universidad. Dado que la metodología exige ciertos puntos básicos fue necesario introducir modificaciones, como por ejemplo incorporar un rol nuevo que libere al cliente de la escritura de historias (Analista), recorte de horas de trabajo (XP supone 40 horas semanales – GXP 15 horas semanales), el verificador asume la responsabilidad de escribir las pruebas funcionales y validarlas con el cliente, se modificó también el concepto de cliente “on site” o cliente en el lugar ya que se pactaban reuniones semanales con el y el equipo de desarrollo. Los equipos de desarrollo encontraron dificultades al momento de realizar las pruebas tanto unitarias por parte de los desarrolladores como también las pruebas funcionales por parte del verificador, ya que la herramienta usada (Racional Robot) hace fuerte uso de la interfaz gráfica, la cual estaba en constante modificación, lo cual hacia perder varias horas en retrabajo por parte de quienes realizaban los scripts de pruebas. No queda claro el concepto de unidad, ya que por ejemplo en Java una unidad pede ser considerada una clase y verificarla con jUnit, en cambio en GeneXus tenemos el concepto de “objeto GeneXus” (transacción, reporte, procedimiento y webpanel), e intentar probar un procedimiento con Rational Robot en una prueba unitaria resultaba compleja. Lo cual llevaba un entrenamiento adicional sobre la herramienta Rational Robot, cuyo resultado era que el test unitario se realizara “a mano” o no se realizara (esto implicaría un desviamiento total sobre la metodología ya que se exige que las pruebas sean automatizadas) y dejando para probar directamente la unidad dentro de la prueba funcional. Una de las prácticas claves en XP es la programación en pares, dicha práctica se debería seguir como en XP tradicional, pero dado que los integrantes de los equipos tienen discordancia horaria es difícil conseguir pares para rotar dos veces a la semana. Como solución a este problema surge la idea de juntarnos los fines de semana y luego de la reunión semanal, continuar con el desarrollo haciendo el cambio de par respectivo. Esto no quiere decir que XP no sea aplicable sino que se necesitan ciertas condiciones para encarar un proyecto con esta metodología, y es difícil conseguirlo en el contexto de la facultad.
Página 17 de 19
Gestión de Software
Testing en eXtreme Programming
El tester es el responsable de ayudar al cliente a seleccionar y escribir las pruebas de aceptación para cada historia de usuario. Tiene la responsabilidad de ayudar al cliente a tomar las decisiones correctas sobre que significa la calidad para su proyecto. El tester escribe las pruebas de ACEPTACION, pero NO las pruebas UNITARIAS, esto lo debe hacer cada desarrollador. La práctica de programación por pares puede resultar muy buena si los pares se llevan bien y son unidos, las ventajas se ven en que el código se encuentra bajo revisión continua. Se ve una mejora en la calidad del código ya que se utiliza siempre el estándar. Los casos de prueba se pueden discutir con el par al momento de implementar, lo que puede llevar a tener casos de prueba más completos. La práctica de “diseño simple” no quiere decir un mal diseño, sino el diseño óptimo que se ajuste solo a las necesidades. Unas de las principales ventajas que vemos en XP es que todo el equipo es conciente del estado del proyecto, y adquiere un conocimiento global sobre las funcionalidades (o historias) del mismo, ya que la continua rotación de los pares evita la aparición de expertos en determinadas áreas del sistema. Las pruebas unitarias como se dijo anteriormente son una actividad fundamental en XP, deben ser automatizadas y elaboradas antes y durante la implementación de un módulo. Luego de terminada la implementación del mismo las pruebas unitarias deben ser todas correctas, asegurando así el buen funcionamiento del módulo, es necesario que todas las pruebas sean correctas para poder integrar el módulo nuevo al sistema existente. Todas las pruebas deben ser automatizadas ya que en cada integración deben correrse todas las unitarias como funcionales y deben pasar a ser 100% correctas, de lo contrario es factible que el módulo nuevo tenga conflictos con el sistema de la etapa anterior. La automatización de las pruebas Fomentan el cambio: facilitan la refactorización, puesto que permiten hacer pruebas sobre los cambios y así asegurarse de que los nuevos cambios no han introducido errores. Simplifica la integración: Puesto que permiten llegar a la fase de integración con un grado alto de seguridad de que el código está funcionando correctamente. De esta manera se facilitan las pruebas de integración. Documenta el código: Las propias pruebas son documentación del código puesto que ahí se puede ver cómo utilizarlo. Los errores están más acotados y son más fáciles de localizar: dado que tenemos pruebas unitarias que pueden desenmascararlos. En XP las pruebas de aceptación son pruebas de caja negra y debería ser responsabilidad del cliente la escritura de casos y definición de criterios para la aceptación del sistema. Las pruebas de aceptación en XP permiten verificar que las funcionalidades de cada iteración se cumplan correctamente. Se debe definir un criterio de aprobación de las mismas que puede no ser de un 100% de efectividad. Se deben presentar los resultados de las mismas a todo el equipo de desarrollo.
Página 18 de 19
Gestión de Software
[BECK, Kent. 2000]
Testing en eXtreme Programming
Extreme Programming Explained: Embrance Change.
Addison-Wesley.
Massachusetts:
[CRISPIN. 2001] CRISPIN Lisa. 2001. Extreme Rules of the Road. [online] [citado 12/04/2004]. Disponible en internet: [CRISPIN, HOUSE. 2002] CRISPIN, L.; TIP HOUSE. 2002. Testing Extreme Programming. Massachusetts: Addison-Wesley. [JEFFRIES, Ron. 1999b] Extreme Testing . [online] [citado 12/04/2004]. Disponible en internet: Memoria organizacional 2003 . [FACULTAD DE INGENIERÍA] Disponible en internet:
Página 19 de 19