• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Presentación: xUnit y Junit
 

Presentación: xUnit y Junit

on

  • 7,340 views

http://programadorphp.org/

http://programadorphp.org/
Charla que dí para la asignatura Diseño de Software Orientado a Objetos de la Universidad de Granada en el año 2007

Statistics

Views

Total Views
7,340
Views on SlideShare
4,891
Embed Views
2,449

Actions

Likes
4
Downloads
0
Comments
0

3 Embeds 2,449

http://www.programadorphp.org 2438
http://www.slideshare.net 10
http://wildfire.gigya.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Presentación: xUnit y Junit Presentación: xUnit y Junit Presentation Transcript

    • ENTORNOS DE UNIDADES DE PRUEBA xUnit JUnit
    • ENTORNOS DE PRUEBA I ¿Qué son?: La mayoría de la gente que escribe programas tiene como mínimo algo de experiencia con unidades de prueba. Si alguna vez has escrito unas pocas líneas de código para probar que lo que has programado es correcto, habrás construido una. Por otra parte,las grandes aplicaciones tienen un conjunto muy extenso y variado de casos de prueba que son ejecutados repetidamente y se añaden a la salida del proceso de desarrollo. La unidad de prueba es útil en todos los niveles de programación.
    • ENTORNOS DE PRUEBA II La relación entre las unidades de prueba con el código de una aplicación se constituye mediante la comunicación usando métodos:
    • ENTORNOS DE PRUEBA III:Características - ¿Para qué sirven? Pueden ser usados para comprobar muchas arquitecturas complejas. Es mucho más fácil que desarrollar test independientes y además producen pruebas efectivas y fiables:permiten un desarrollo rápido de nuestra aplicación. 2 tipos :dependiendo de la cantidad de accesos a los procesos internos que puedan estar siendo probados – cajas negras : funcional ● ejecuta un programa y comprueba que devuelve un código determinado – o cajas blancas: estructurales ● acceden a la estructura del código que está siendo probado
    • ENTORNOS DE PRUEBA IV:Conclusiones Usar entornos de prueba obliga a realizar una buena práctica del desarrollo orientado a objetos ya que están escritas para probar sólamente las partes públicas de los objetos a testar. Esto cubre el diseño de los objetos con discrección, interfaces de prueba y un mínimo de comportamiento ocultado complejo. La mayoría de los lenguajes orientados a objetos nos brindan protección de acceso, no permitiendo el acceso externo desde otras clases a partes protegidas o privadas. Los desarrolladores escriben patrones de programación así, diseñan y construyen código. Estas pruebas suelen probar elementos de código de bajo nivel, así como métodos e interfaces.
    • Pruebas para el desarrollo conducido TDD: Test Driven Development, también conocidas como primeras pruebas de programación son una de las más significantes y completas prácticas utilizadas como programación extrema (XP:Extreme Programming) y otras metodologías de Desarrollo Ágil. Los entornos de prueba consiguen su máxima utilidad cuando son usados para habilitar estos TDD,aunque siguen siendo útiles cuando TDD no se sigue. La regla dominante de TDD puede ser resumida como la de "prueba dos veces, programa una vez," por analogía a la regla del carpintero:"mide dos veces, corta una vez."; refiriéndose al proceso de 3 pasos que tiene que ver con cualquier cambio en el código: – 1.Escribir una prueba para el nuevo código y comprobar si falla. – 2.Escribir el nuevo código , haciendo "las cosas más simples que posiblemente podrían funcionar". – 3.Comprobar que se completa correctamente la prueba, y replanteamos el código.
    • Éstos tres básicos pasos son el ciclo TDD El paso 1 es escribir la prueba , ejecutarla y comprobar los posibles fallos. Los fallos son importantes porque nos sirven para validar que la prueba ha fallado como se esperaba.Suele ser una tentación el saltarse la ejecución y comprobar que realmente falla. No debe de hacer esto. En el paso 2 el código es escrito para hacer que el test sea superado.Una sabia pauta es hacer "lo más simple que posiblemente podría funcionar." En el paso 3, la prueba tiene éxito, verificando el nuevo código y su prueba. En este punto, el nuevo código puede ser replanteado de nuevo,éste es un concepto de la ingeniería de software definido como "comportamiento-preservando la transformación." Más formalmente, el replanteamiento (refactoring) es el proceso de transformar código para mejorar su diseño interno sin cambiar su funcionalidad externa.
    • Conclusiones de TDD I Las unidades de prueba tienen valor en cuanto a la capacidad de demostrar que la nueva funcionalidad añadida a un programa realmente funciona. Escribir la prueba fuerza a pensar por adelantado en el diseño ideal del nuevo código. Así, de una manera disimulada y sutil, TDD hace toda la nueva pieza del desarrollo con un proceso metódico, bajo el diseño de software. Una vez que la nuevas pruebas y funcionalidades de la unidad estén en su lugar, la prueba de unidad sirve como el ejemplo definitivo de funcionamiento para comprobar cómo el nuevo código se supone que va a ser utilizado. Por estas razones, el tiempo que se perdió escribiendo pruebas de unidad no está gastando sólamente esfuerzo. Las inversiones en las pruebas son proporcionales al diseño.
    • Conclusiones de TDD II Al eliminar errores,depurando, se debe escribir primero una prueba de unidad que falle debido al error esperado. Esto es un esfuerzo útil en sí mismo, porque se determina exactamente cómo ocurre éste error. Una vez que la prueba de unidad está en lugar y falle,hay que fijar el error y volver a efectuar la prueba para verificar que el bug está solucionado. Aparte de fijar el error, este proceso tiene la ventaja adicional de crear una prueba que lo captrue. Si el bug se reintroduce siempre, la prueba fallará y el problema persistirá. Siguiendo el ciclo de TDD, se puede escribir código sin errores como sea humanamente posible en un primer intento, en otras palabras ,escribir de una sóla vez. El proceso da una indicación clara de que una parte del trabajo está hecho. Cuando una nueva unidad de prueba se escribe y después falla, la tarea está a medio camino de ser completada. No se puede mover a ningún otro sitio hasta que las pruebas sean superadas.
    • La Familia xUnit Kent Beck publicó un entorno de unidad de pruebas para el lenguaje Smalltalk en 1999. La arquitectura de esta unidad (SUnit) representa un equilibrio ideal entre simplicidad y utilidad. Más tarde, Erich Gamma portó SUnit a Java, creando JUnit, que se volvió a convertir en CppUnit,NUnit,PyUnit, XMLUnit, y conversiones a muchos otros lenguajes. Un impresionante conjunto de entornos de unidad de prueba fueron construidos con el mismo modelo actual. Estos entornos se conocen como la familia de herramientas xUnit. Todo es software libre,de fuente abierta.
    • Miembros de la familia xUnit Algunos de los más populares entornos de prueba xUnit junto con los lenguajes a los que están orientados y el dominio de las pruebas: – JUnit :La referencia de la implementación de xUnit, es en gran medida el entorno más usado y extendido de unidad de prueba.Está implementada dentro y usada desde Java. – CppUnit :Conversión a C++ desde JUnit, sigue muy de cerca el modelo de JUnit. – NUnit :Más bien que una conversión directa de JUnit, tiene una puesta en práctica específica de .NET, que sigue generalmente el modelo de xUnit. Se escribe en C # y puede ser utilizado probar cualquier lenguaje de .NET, incluyendo C #, VB.Net, J #, y C++ manejado. – PyUnit :La versión Python de xUnit. Está incluida como un componente estándar de Python 2.1.
    • Miembros de la familia xUnit II SUnit :También conocida como SmalltalkUnit, es la xUnit original, y las bases de la arquitectura de xUnit architecture. Está escrita en lenguaje Smalltalk y se usa desde éste. vbUnit:Es la xUnit para Visual Basic (VB). Está escrita en este lenguaje y soporta la construcción de pruebas en VB asó como desarrollo de COM (componentes). utPLSQL :Es la xUnit para el lenguaje PL/SQL de Oracle. Está escrita en PL/SQL y se usa desde éste lenguaje. MinUnit : Un gran ejemplo de un pequeño pero funcional entorno de unidades de prueba. Está implementado en tres líneas de C pero se usa para probar código en éste lenguaje.
    • JUnit El Entorno de unidades de prueba JUNIT es la implementación de xUnit. Como su nombre dice, ha sido desarrollada y usada con Java. Es el mas usado y analizado entorno de unidades de pruebas de software hoy por hoy.JUnit es la base de utilidades de prueba mas específicas, como Cactus, Jester, JunitPerf, y muchos mas e integrado con otros como Ant. El objeto de JUnit es proporcionar un entorno para construir y ejecutar unidades de pruebas. La distribución JUnit también es un buen ejemplo de un simple y sólido producto software que ha sido creado usando desarrollo guiado con pruebas. Es importante reseñar que el código de JUnit es muy instructivo. JUnit es software abierto (opensource) y podemos obtener su código desde www.junit.org , siendo la última versión la 3.8.1.
    • Arquitectura de JUnit JUnit contiene 75 clases concretas y una serie de clases internas e interfaces. Está organizado en paquetes como se muestra a continuación
    • Arquitectura del paquete junit.framework La arquitectura de junit.framework sigue el modelo de la arquitectura xUnit. En particular nos muestra el elemento Test, que está implementado por las clases TestCase y TestSuite. La clase abstracta TestCase es el padre de todas las clases de unidades de prueba. Las clases principales usadas cuando se construyen las unidades de prueba son TestCase, TestSuite y TestRunner.
    • Arquitectura del paquete junit.framework
    • Uso de JUnit Las clases de prueba en JUnit son subclases de TestCase. Las pruebas pueden ser construidas de muchas formas, pero el mejor enfoque es el siguiente: El nombre de la clase de prueba comienza con el nombre del objeto que está siendo testeado y finalizarlo con “Test”. Las clases Test contienen un método separado para cada comportamiento a ser probado. Las condiciones de prueba son comprobadas con métodos de comprobación. Los resultados obtenidos en las pruebas de comprobación son “éxito” o “fallo”. Si la comprobación falla, el método de prueba devuelve el control inmediatamente. Si la comprobación es satisfactoria, la ejecución de los métodos de prueba continuan. Cómo un método de prueba solamente comprueba un comportamiento simple, en la mayoría de los casos cada método de prueba debería contener solamente un test de comprobación. Si hay objetos que son compartidos por los métodos de prueba, los objetos deben ser inicializados en el método setUp() y destruidos en el método tearDown(). Estos métodos son llamados antes y después de cada llamada a pruebas de método.
    • Ejemplo de uso de JUnit PruebaLibreria.javaimport junit.framework.*; import java.util.*; public class PruebaLibreria extends TestCase { private Libreria liberia; public void setUp( ) throws Exception { libreria = new Libreria( ); libreria.insertarLibro(new Libro( "Cosmos", "Carl Sagan" )); libreria.insertarLibro(new Libro( "Contact", "Carl Sagan" )); libreria.insertarLibro(new Libro( "Solaris", "Stanislaw Lem" )); libreria.insertarLibro(new Libro( "American Beauty", "Allen M Steele" )); libreria.insertarLibro(new Libro( "American Beauty", "Edna Ferber" )); } //….
    • Ejemplo de uso de JUnit II public void tearDown ( ) { libreria.empty( ); libreria = null; } public void testGetLibrosPorTitulo ( ) { Vector Libros = libreria.getLibrosPorTitulo( "American Beauty" ); assertEquals( "se encontró un número incorrecto de Libros", 2, Libros.size( ) ); } public void testGetLibrosPorTitulo( ) { Vector libros = libreria.getLibrosPorTitulo( "Carl Sagan" ); assertEquals( "2 libros no encontrados", 2, libros.size( ) ); } public void testVacio( ) { libreria.empty( ); assertEquals( "libreria no está vacía", 0, libreria.getNumLibros( ) ); } } Como podemos observar en LibreriaTest realizamos pruebas, creando una instancia de Libreria. El objeto Libreria es creado e inicializado con una serie de Libros en la función setUp(); su contenido interno es borrado posteriormente en tearDown().
    • Ejecutando JUnit Cada método de prueba verifica un comportamiento diferente de la clase Libreria con un solo test. Aunque los test pueden modificar el objeto Libreria, (como puede verse en el método testEmpty(), el test garantiza que cada prueba se ejecuta en un entorno libre, sin dependencias de los resultados de otras. Los test son ejecutados usando una de las utilidades TestRunner suministradas con JUnit. El mas simple y mas fácil de estos es TextTestRunner: Ejemplo de uso de TextTestRunner ejecutando LibreriaTest: $ java junit.textui.TestRunner PruebaLibreria.........Time: 0.01 OK (3 tests)
    • Ejecutando JUnit : varios tests Esto a veces es interesante para añadir múltiples test que pueden ejecutarse juntos. La clase TestSuite se usa para contener una colección de test. El ejemplo siguiente muestra una clase LibreriaTest la cual crea un TestSuite conteniendo un número de clases de prueba. El método estático suite() crea y devuelve el TestSuite: PruebasLibreria.javaimport junit.framework.*; public class PruebasLibreria extends TestSuite { public static Test suite( ) { TestSuite suite = new TestSuite( ); suite.addTest(new TestSuite(PruebaLibro.class)); suite.addTest(new TestSuite(PruebaLibreria.class)); suite.addTest(new TestSuite(PruebaDBLibreria.class)); suite.addTest(new TestSuite(PruebaFuncLibreria.class)); return suite; } }
    • Ejecutando JUnit : resultados Cuando PruebasLibreria es ejecutado usando TexTestRunner, todos los métodos de pruebas en cada clase de pruebas son buscados y ejecutados como se puede ver a continuación: $ java junit.textui.TestRunner PruebasLibreria.................Time: 0.851OK (17 tests)
    • GUI JUnit::TestRunner La versión Swing de TestRunner es llamada por PruebasLibreria(Libr ayTests) como se muestra: $ java junit.swingui.TestRunne r PruebasLibreria
    • Extensiones xUnit Además de los xUnits, están disponibles muchas herramientas adicionales que amplían la funcionalidad de los entornos existentes de unidad de prueba , en dominios especializados, actúan más bien como herramientas independientes.
    • Extensiones xUnit : tipos más conocidos XMLUnit :Una extensión xUnit para soportar testeo XML. Las versiones que existen son para usar con JUnit y NUnit: una extensión JUnit que soporta escritura de código funcional y pruebas escalares. Está escrita en Java y se usa desde este lenguaje. Cactus :Una extensión JUnit para probar la unidad del código de servidores como servlets (objetos que corren dentro del contexto de un servidor de aplicaciones, como Tomcat), JSPs, o EJBs. Está escrita en Java y se usa con este lenguaje. JFCUnit :Una extensión JUnit que soporta pruebas gráficas (con GUI: graphic user interface) para las aplicaciones que usan Swing, de Java. Está escrita en Java y se usa desde éste.
    • Extensiones xUnit : tipos más conocidos NUnitForms :Extesnión NUnit que soporta pruebas de GUI de alpicaciones "Windows Forms". Está escrita en C# y puede ser usada por cualquier lenguaje de la plataforma .NET. HTMLUnit : Una extensión para JUnit que prueba aplicaciones basadas en la web.Simula un navegador y está orientado a escribir pruebas que usan páginas en HTML. HTTPUnit :Otra extensión JUnit que prueba aplicaciones basadas en la web.Orientada a escribir pruebas que tratan con objetos de peticiones y respuestas HTTP. Jester :Una "provechosa" extensión que encuentra automáticamente el código que no se cubre por las unidades de prueba, mostrándolo.Existen versiones para Python (Pester) y NUnit (Nester). Existen muchas otras herramientas de cobertura de código con funcionalidades similares.
    • La Arquitectura xUnit Todas las xUnits tienen la misma arquitectura básica. Ahora describiremos los fundamentos de xUnit, usando JUnit como referencia de ejemplo, hasta el momento es la más usada de las xUnits. La otras xUnits varían en sus detalles de implementación,pero siguen el mismo patrón y generalmente contienen el mismo conjunto clave de clases y conceptos. Las clases de "alto nivel" (key-class: sin constructor,de las que podemos usar sus métodos y propiedades) son TestCase, TestRunner, TestFixture, TestSuite, y TestResult.
    • xUnit::TestCase La clase más elemental de xUnit, es la base de una unidad de prueba Es una clase abstracta, el padre de todas las unidades de prueba de xUnit. Todas las unidades de prueba heredan de esta clase, para crear una unidad de pruebase define una clase prueba que es un descenciente de la clase elemental a la que se le añade un método prueba.
    • Ejemplo: PruebaLibro.java, una clase basada en TestCase PruebaLibro.java import junit.framework.*; public class PruebaLibro extends TestCase { public void testConstructLibro( ) { Libro libro = new Libro("El Alquimista"); assertTrue( libro.getTitulo( ).equals("El Alquimista") ); } }
    • Ejemplo. PruebaLibro,una clase basada en TestCase El método testConstructLibro() usas assertTrue() para verificar el valor del título del libro. Las condiciones de prueba son siempre evaluadas por los métodos "assert" ( asegurar ) del entorno de pruebas. Si una condición se evalúa como TRUE , el entorno incrementa el contador de pruebas superadas, en otro caso, si es FALSE, ocurre un fallo en la prueba y el entorno almacena los detalles, incluyendo la posición del error en el código.Después de un fallo, el entorno se salta el resto de las líneas de código para ese método,ya que el resultado de la prueba ya se sabe. PruebaLibros prueba la clase Libro:Libro.java public class Libro { private String titulo = ""; Libro(String titulo) { this.titulo = titulo; } String getTitulo( ) { return titulo; } }
    • Ejecutando el ejemplo de TestCase PruebaLibro puede ser ejecutada añadiendo una función main() que llame al método de prueba del constructor:PruebaLibro.java import junit.framework.*; public class PruebaLibro extends TestCase { public void testConstructLibro( ) { Libro libro = new Libro("El Alquimista"); assertTrue( libro.getTitulo( ).equals("El Alquimista") ); } public static void main(String args[]) { PruebaLibro prueba = new PruebaLibro( ); prueba.testConstructLibro( ); } }
    • Ejecutando el ejemplo de TestCase II Compilando y ejecutando PruebaLibro produce una carencia en la salida bastante decepcionante que no da demasiada confianza puesto que podría haber sucedido cualquier cosa realmente. > javac PruebaLibro.java > java PruebaLibro (Para que los comandos funcionen como se muestra, junit.jar y el directorio que contiene las clases de pruebas deben de estar en la variable de entorno classpath de Java . ) Los resultados serían más interesantes si PruebaLibro estuviera hecho para fallar , por ejemplo,cambiando la condición de assertTrue() por FALSE. > java PruebaLibro Exception in thread "main" junit.framework.AssertionFailedError at junit.framework.Assert.fail(Assert.java:47) at junit.framework.Assert.assertTrue(Assert.java:20) at junit.framework.Assert.assertTrue(Assert.java:27) at PruebaLibro.testConstructLibro(PruebaLibro.java:7) at PruebaLibro.main(PruebaLibro.java:12) Ahora podemos comprobar que la unidad de prueba del entorno está haciendo su trabajo, ejecutando la prueba y obteniendo como resultado el fallo de la misma. Esto demuestra que un entorno xUnit puede ser usado de una forma muy simple y directa.
    • xUnit:: TestRunner I Las unidades de prueba básicas pueden ser construidas en TestCase sin ningún conocimiento adicional del entorno. Sin embargo, xUnit tiene muchas otras funcionalidades que ofrecer. Una de las piezas más valiosas es TestRunner. Una clase TestRunner devuelve detalles acerca de los resultados de la prueba y la simplifca. Es un objeto bastante complejo que en JUnit, viene en tres "sabores": AWT TestRunner, Swing TestRunner y TestRunner textual (llamado también TextTestRunner) El propósito de estas clases es ejecutar una o más clases TestCases y devolver los resultados.
    • xUnit :: TestRunner II
    • xUnit :: TestRunner II Los métodos más importantes de TextTestRunner son run( ), al que se le pasa una prueba para ejecutar y main( ), que hace de TextTestRunner una clase ejecutable, y se ejecutará con la clase de prueba PruebaLibro como su argumento. Encontrará el método de prueba testConstructLibro y lo ejecutará. Podemos eliminar el método main( ) de la clase PruebaLibro, ya que no la vamos a usar para ejecutar la prueba. Código replanteado de la clase PruebaLibro, hecha de una forma más simple PruebaLibro.java import junit.framework.*; public class PruebaLibro extends TestCase { public void testConstructLibro( ) { Libro libro = new Libro("El Alquimista"); assertTrue( libro.getTitle( ).equals("El Alquimista") ); } } PruebaLibro se reduce hasta lo esencial. Ahora, usamos TextTestRunner para ejecutarla:
    • xUnit :: TestRunner III Usando TestRunner no sólo se elimina código innecesario de PruebaLibro sino que además provee un resultado mejor configurado de cómo muchas de las pruebas fueron ejecutadas y cuánto tiempo se tomó en hacerlo. Las clases Test (de pruebas) suelen tener varios métodos de prueba, TestRunner las encontrará todas y las ejecutará,para ello se usa "test" para empezar el nombre del método. PruebaLibro con un segundo método añadido. La nueva prueba comprueba el autor del libro: PruebaLibro.java import junit.framework.*; public class PruebaLibro extends TestCase { public void testConstructLibro( ) { Libro libro = new Libro("El Alquimista", ""); assertTrue( libro.getTitulo( ).equals("El Alquimista") ); } public void testAutor( ) { Libro libro = new Libro("El Alquimista", "Paulo Coelho"); assertTrue( libro.getAutor( ).equals("Paulo Coelho") ); } }
    • xUnit :: TestRunner IV El atributo autor y su función de acceso getAutor() han de ser añadidos a la clase Libro: Libro.java public class Libro { private String titulo = ""; private String autor = ""; //Constructor con 2 parámetros Libro(String titulo, String autor) { this.titulo = titulo; this.autor = autor; } public String getTitulo( ) { return titulo; } public String getAutor( ) { return autor; } } – Ejecutando PruebaLibro se muestra que el entorno está corriendo dos pruebas: > java junit.textui.TestRunner PruebaLibro .. Time: 0.01 OK (2 tests)
    • xUnit :: TestRunner : resultados Se imprime un punto cuando cada prueba es ejecutada, como un indicador de progreso. La salida de la prueba concluye con el número de pruebas y el tiempo utilizado. Muchos de las xUnits incluyen una interfaz gráfica (GUI TestRunner) para ofrecer un entorno visual con objetos.Los resultados son mostrados en verde si todas las pruebas funcionaron bien , o en rojo si no lo hicieron. Esto es el origen de las barras verdes y rojas. El ciclo TDD a veces se describe como "Replanteamiento Rojo- Verde" por esto. Primero, se implementa una nueva prueba que falla, provocando una barra roja; después se hace el cambio más fácil posible que rectifique la barra en una verde; por último, se hace el replanteamiento del código "feo" que se introdujo.
    • xUnit:: TestFixture Para explicar las pruebas de acoplamiento hay que dar otro concepto importante de xUnit,necesitamos un ejemplo de unidad de prueba más complejo; añadimos la clase Libreria para permitir que se puedan insertar más de un Libro y para obtener el número de ellos insertados. Versión inicial de PruebaLibreria: PruebaLibreria.java import junit.framework.*; import java.util.*; public class PruebaLibreria extends TestCase { public void testInsertarLibro( ) { Libreria libreria = new Libreria( ); libreria.insertarLibro(new Libro("El Alquimista", "Paulo Coelho")); libreria.insertarLibro(new Libro("Solaris", "Stanislaw Lem")); Libro libro= libreria.getLibro( "El Alquimista" ); assertTrue( libro.getTitulo( ).equals("El Alquimista") ); libro = libreria.getLibro( "Solaris" ); assertTrue( libro.getTitulo( ).equals("Solaris") ); } public void testTamLibreria( ) { Libreria libreria = new Libreria( ); libreria.insertarLibro(new Libro("El Alquimista", "Paulo Coelho")); libreria.insertarLibro(new Libro("Solaris", "Stanislaw Lem")); assertTrue( libreria.getNumLibros( ) == 2 ); } }
    • xUnit:: TestFixture II Los dos métodos de prueba implementados: testInsertarLibro( ) añade dos Libros a la Libreria, después usa getLibro( ) para comprobar que la inserción no falló. testTamLibreria( ) añade también dos Libros y luego comprueba que getNumLibros( ) devuelve "2". Ahora añadimos las funcionalidades para pasar las pruebas a la clase Libreria: Libreria.java import java.util.*; public class Libreria { private Vector libros; Libreria( ) { libros = new Vector( ); } public void insertarLibro( Libro libro) { libros.add( libro ); } public Libro getLibro( String titulo ) { for ( int i=0; i < libros.size( ); i++ ) { Libro libro= (Libro) libros.elementAt( i ); if ( libro.getTitulo( ).equals(titulo) ) return libro; } return null; } public int getNumLibros( ) { return libros.size( ); } }
    • xUnit:: TestFixture III Libreria usa ahora un Vector que contiene una colección de Libros. El método getNumLibros( ) devuelve el número de Libros de la colección. Los métodos insertarLibro( ) y getLibro( ) añaden y eliminan un Libro de la colección Cuando usamos TextTestRunner para ejecutar PruebaLibreria ambos métodos superan la prueba: > java junit.textui.TestRunner PruebaLibreria .. Time: 0.05 OK (2 tests)
    • xUnit:: TestFixture IV PruebaLibreria tiene unos cuantos problemas... El primero y antes de nada,la cantidad de código duplicado entre dos métodos de prueba es "fastidioso" ya que los dos crean una prueba de Libreria y añaden dos libros a ella. El segundo,otra preocupación es que pasaría uno de los asserts falla: el resto del código del método de la prueba no se ejecutaría y ningún objeto es destruido. En Java, el recolector de basura capturaría los objetos y los borraría de la memoria automáticamente, pero las unidades de prueba suelen usar objetos o recursos que deben ser cerrados o borrados explícitamente. Una forma de no tener que estar pendiente de la duplicación de código es hacer que la Libreria de la prueba sea un miembro de la clase PruebaLibreria y hacer que la primera prueba la inicialice y añada los dos elementos iniciales. La segunda prueba podría asumir que aquella funcionó correctamente,entonces se ejecuta y queda limpia.
    • xUnit:: TestFixture V Desafortunadamente ,esta solución añade más problemas potenciales, si la primera prueba falla, la segunda también debe hacerlo puesto que sus condiciones iniciales son incorrectas, incluso aunque no hubiese nada mal en su propia prueba. La segunda prueba siempre fallará a menos que la primera sea ejecutada antes que ella,así que no pueden ser ejecutadas por separado o en orden inverso.Además,si cualquiera de las dos fallara resultaría en que las cosas no terminarían de una forma limpia(no se llama a los destructores,etc.) En general, las unidades de prueba bien escritas están aisladas. Una prueba aislada no depende de ningún modo en los resultados de otras pruebas. Para asegurar el aislamiento, las pruebas no deben de compartir objetos que cambien.
    • xUnit:: TestFixture VI Las pruebas que tienen interdependencias están emparejadas. En PruebaLibreria, si uno de los métodos prueba asume que el otro deja la clase Libreria en un cierto estado, es un claro ejemplo de una prueba con emparejamiento (en este caso de métodos). La arquitectura xUnit nos ayuda para asegurarnos de que las pruebas estén aisladas con pruebas de acoplamiento, que son un entorno de prueba usado en muchas pruebas. Están implementadas como TestCase con múltiples métodos de pruebas que comparten objetos que representan el entorno de pruebas común.
    • Relación entre TestFixture y TestCase La clase hija aunque se llame TextFixture es TestCase,cada una de ellas es implícitamente una TestFixture, aunque puede no actuar como tal. El comportamiento de TestFixture viene a ejecutarse cuando varios métodos prueba tienen objetos en común. La función setUp() es llamada antes de cada método de prueba, estableciendo el entorno para la prueba.La función tearDown( ) siempre es llamada después de cada método de prueba para limpiar este entorno, incluso si ha ocurrido un error.
    • Relación entre TestFixture y TestCase II Así, aunque las pruebas usen los mismos objetos, pueden hacer cambios sin posibilidad de que afecte a la siguiente función prueba. El comportamiento de TestFixture crea y destruye efectivamente la clase de prueba cada vez que son llamados sus métodos prueba. Esto desemboca en que las pruebas son aisladas. Algunas xUnits (como CppUnit) tienen una clase real o interface llamada TestFixture de la que desciende TestCase ,mientras que otras (JUnit) sólo permiten a TestCase actuar como una clase TestFixture. Escribir pruebas como TestFixtures tiene una serie de ventajas. Los métodos de prueba pueden compartir objetos pero siguen ejecutándose de forma aislada; el emparejamiento de pruebas es minimizado y los métodos de prueba que comparten código pueden ser agrupados en la misma clase TestFixture. La duplicación de código entre pruebas se ve reducida. Se garantiza la limpieza en el código,de forma que será ejecutada tanto si una prueba falla como si no. Por último , los métodos de prueba pueden ser ejecutados en cualquier orden ,ya que son aislados.
    • Ejemplo usando xUnit::TestFixture PruebaLibreria implementada como un TestFixture. En el ejemplo, el entorno compartido de pruebas acopladas contiene una instancia de Libreria y dos Libros. import junit.framework.*; import java.util.*; public class PruebaLibreria extends TestCase { private Libreria libreria; public void setUp( ) { libreria = new Libreria( ); libreria.insertarLibro(new Libro("El Alquimista", "Paulo Coelho")); libreria.insertarLibro(new Libro("Solaris", "Stanislaw Lem")); } public void tearDown( ) { } public void testGetLibros( ) { Libro libro = libreria.getLibro( "El Alquimista" ); assertTrue( libro.getTitulo( ).equals( "El Alquimista" ) ); libro = libreria.getLibro( "Solaris" ); assertTrue( libro.getTitulo( ).equals( "Solaris" ) ); } public void testTamLibreria( ) { assertTrue( libreria.getNumLibros( ) == 2 ); } }
    • Ejemplo usando xUnit::TestFixture II La mejora de estilo con respecto a la versión anterior de PruebaLibreria es evidente: la duplicación de código ha desaparecido, los métodos de prueba sólo contienen sentencias específicas relacionadas con las condiciones de las pruebas y las pruebas son más fáciles de entender. Nótese que el método de prueba llamado testInsertarLibros() se llama ahora testGetLibros( ) para describir mejor lo que hace. Cuando se ejecuta PruebaLibreria, la secuencia de la función es: setUp( ) testGetLibros( ) tearDown( ) setUp( ) testTamLibreria( ) tearDown( ) Las llamadas a setUp( ) y tearDown( ) inicializan y limpian la prueba de acoplamiento cada vez que se llama al método, así aisla al resto de pruebas.
    • xUnit:: TestSuite Hace mucho, la revisión de xUnit se centraba en escribir clases en una sóla unidad de pruebas,a veces con multitud de métodos de prueba. ¿Qué pasó con las pruebas de muchas clases de unidades de prueba?,después de todo,cada objeto producido debería tener su unidad de prueba correspondiente. xUnit contiene una clase para agregar unidades de prueba llamada TestSuite,que está relacionada de cerca con TestCase, ya que ambas son descendientes de la misma clase abstraacta
    • xUnit:: TestSuite II La figura muestra la interfaz de la prueba Test y cómo TestSuite y TestCase la implementan.
    • xUnit:: TestSuite III TestSuite, TestCase tiene como su padre,la interface Test,que contiene el método run() y usa el entorno para ejecutar pruebas y reunir sus resultados. Ya que TestSuite implementa run(), puede ser ejecutada como una TestCase. Cuando una TestCase es ejecutada,sus métodos de prueba también lo son. Cuando una TestSuite es ejecutada, sus TestCases también.Las clases TestCases son añadidas a TestSuite usando la función addTest();debido a que TestSuite es en sí misma una clase Test, una TestSuite puede contener otras TestSuites, permitiendo al intrépido desarrollador el poder construir jerarquías de TestSuites y TestCases.
    • Ejemplo de xUnit::TestSuite Clase TestSuite derivada : PruebasLibreria que contiene PruebaLibro y PruebaLibreria: PruebasLibreria.java import junit.framework.*; public class PruebasLibreria extends TestSuite { public static Test suite( ) { TestSuite suite = new TestSuite( ); suite.addTest(new TestSuite(PruebaLibro.class)); suite.addTest(new TestSuite(PruebaLibreria.class)); return suite; } }
    • Ejemplo de xUnit::TestSuite II Una instancia de TestSuite es creada y añadida a PruebasLibreria por cada una de las clases de prueba. Ésta es una forma rápida de añadir todas los pruebas al conjunto suite de una sóla vez. La función addTest( ) debe ser usada además para añadir métodos al conjunto de pruebas de forma individual, ejemplo: – suite.addTest(new PruebaLibreria("testInsertarLibros")); Para ser usada de esta forma,una instancia de TestCase debe tener un constructor que tome un argumento de tipo cadena que llame al constructor de su padre.El argumento especifica el nombre del método de prueba a ejecutar. Se pueden ejecutar instancias de TestSuite usando una clase TestRunner tal como si ejecutaramos una TestCase. El método estático de TestSuite ,suite( ) se llama para crear el conjunto suite de pruebas a ejecutar. > java junit.textui.TestRunner PruebasLibreria .... Time: 0.06 OK (4 tests) Los resultados muestran que ambos métodos de prueba de las clases de las unidades PruebaLibreria y PruebaLibro han sido ejecutadas, con un total de 4 pruebas.
    • xUnit::TestResult TestResult es el parámetro para ejecutar el método run() de la clase Test. La meta inmediata de la ejecución de unidades de prueba en un sentidoliteral, es acumular los resultados de estas. La clase TestResult sirve a este propósito. Cada vez que una prueba es ejecutada, el objeto TestResult es pasado a una colección de resultados. Figura: La clase TestResult, usada para coleccionar las salidas de las pruebas:
    • xUnit::TestResult II TestResult es un objeto simple,cuenta las pruebas ejecutadas y almacena los pruebas fallidas y los errores de forma que el entorno puede devolver información en base a esto. Éstos fallos y errores incluyen detalles acerca de la localización en el código donde han ocurrido y cualquier descripción asociada a la prueba. La información impresa para el fallo de PruebaLibro es un ejemplo.
    • Resumen de la arquitectura xUnit Las clases TestCase , TestRunner, TestFixture, TestSuite y TestResult representan el núcleo de la arquitectura xUnit.Comprender qué hacen es comprender cómo funciona xUnit.
    • Clases núcleo del entorno de pruebas de la arquitectura xUnit
    • Clases de prueba: PruebasLibreria, PruebaLibreria y PruebaLibro PruebasLibreria es una TestSuite que contiene una PruebaLibro y una PruebaLibreria,ésta es una TestFixture y PruebaLibro es una TestCase. Conceptualmente, TextTestRunner ejecuta PruebasLibreria, que al ejecuta PruebaLibro y PruebaLibreria,las cuales ejecutan sus métodos de forma alternada.