Ingeniería de Software

Practica 5: Realización de pruebas

El objetivo de esta practica es comprender cómo se realizan pruebas unitarias de manera automática utilizando el framework JUnit.

JUnit

JUnit es un framework orientado a la realización de pruebas unitarias en Java. La idea en JUnit es crear una clase de prueba por cada clase que queramos probar. Esta clase de prueba se encarga de:
  1. Instanciar clase a probar
  2. Preparar el caso de prueba (fixture)
  3. Invocar metodos sobre clase a probar
  4. Verificar que los metodos entregan una salida adecuada con respecto a una entrada particular.
Una clase de pruebas hereda siempre de la clase TestCase y contiene un conjunto de metodos que corresponden a las pruebas que se van a realizar. En general, por cada metodo de la clase que queramos probar, vamos a tener un metodo en la clase de prueba. El metodo de la clase de prueba tiene el mismo nombre que el de la clase probada pero con el prefijo test. También hay que notar que se recomienda que las clases de prueba se pongan en package con el mismo nombre pero que inicie por test.

Por ejemplo:

Clase a probar Clase de prueba
package ejemplo;

public class Entero
{
    int m_valor;
   
    public void setValor(int valor)
    {
        m_valor = valor;
    }

    public int getValor()
    {
        return m_valor;
    }

    public int suma(Entero otro)
    {
       m_valor = m_valor+otro.getValor();
       return m_valor;
    }
}
package test.ejemplo;

import ejemplo.Entero;

import junit.framework.*;

public class EnteroTest extends TestCase
{
   private Entero m_entero;

   /**
    * Inicialización de la prueba
   */
   protected void setUp() throws Exception
   {
      m_entero = new Entero();
      m_entero.setValor(5);
   }

   /**
    * Prueba de setValor
   */
   public void testSetValor()
   {
      m_entero.setValor(8);
      assertEquals(m_entero.getValor(),8);
   }

   /**
    * Prueba de getValor
   */
   public void testGetValor()
   {
      assertEquals(m_entero.getValor(),5);
   }

   /**
    * Prueba de suma
   */
   public void testSuma()
   {
      Entero e1 = new Entero();
      e1.setValor(4);
      m_entero.suma(e1);
      assertEquals(m_entero.getValor(),9);
   }

   public static Test suite()
   {
      TestSuite suite = new  TestSuite(EnteroTest.class);
    return suite;
   }
}

Hay que subrayar que la preparación de caso de prueba (o fixture) se realiza en el metodo llamado setUp(). Este metodo siempre es invocado (de forma automática) antes de que se invoque uno de los metodos de la clase de prueba.

Por otro lado, dentro de las pruebas, se usa el metodo assertEquals para verificar que dos valores sean iguales. La clase TestCase provee distintos metodos para comprobar que dos valores sean iguales, distintos o bien que un objeto es nulo o no.

Normalmente, cada test se realiza creando una instancia de la clase de prueba y pasandole en una cadena el nombre del metodo correspondiente a la prueba que se quiere realizar, por ejemplo:

TestCase test = new EnteroTest("testSuma");
test.run();

Sin embargo esto es complicado cuando se tiene un numero elevado de pruebas a realizar. Para ello se utiliza el concepto de suite. Una suite corresponde a un conjunto de tests que se realizan de manera secuencial. La creación de una suite es simplificada con la clase TestSuite. En el ejemplo anterior, el metodo suite (notese que es estático) recibe cómo parametro el nombre de la clase de prueba. Cuando esto ocurre la suite de pruebas va a incluir todos los metodos de prueba que empiezen por test, de ahi la importancia de seguir la convención de nombrado.

NOTA: Al compilar y ejecutar es necesario hacerlo desde la línea de comando.

Una vez que hemos hecho la prueba, es posible complilarla y ejecutarla de la manera siguiente desde la línea de comando:

$javac  -classpath junit.jar -d build/ src/ejemplo/*.java src/test/ejemplo/*.java

$java -cp build/:junit.jar junit.textui.TestRunner test.ejemplo.EnteroTest

...
Time: 0.019
 
OK (3 tests)


Ejercicio 1:

Codificar la clase Entero y su clase de prueba. Efectuar las pruebas y verificar que el resultado sea correcto.

  • Qué pasa si remplazas junit.textui.TestRunner por junit.swingui.TestRunner ?
  • Qué pasa si modificas la clase Entero en el metodo suma y cambias la suma por una resta y luego re-ejecutas las pruebas?
En este primer ejercicio, te puede parecer exagerado que la clase de prueba sea más grande que la clase probada, sin embargo eso no es siempre el caso, como veremos en el ejemplo siguiente.

Ejercicio 2: Checkout y realización de pruebas sobre la arquitectura

En esta segunda iteración de la arquitectura, se incluye un ejemplo de realización de prueba de manera automática. Para probarlo vamos a hacer un checkout.

NOTA: probablemente tengas que hacer un checkout de tu propio proyecto ya que el trunk que se muestra a continuación ya no es accesible.

Paso 1:

$svn checkout svn://www.humbertocervantes.net/proyecto/trunk


Una vez que ha terminado el checkout, vamos a realizar las pruebas

$ant test

test:
    [junit] Running test.mx.uam.ingsoft.pluginadmin.AdministradorPluginsImplTest    [junit] Tests run: 7, Failures: 0, Errors: 0, Time elapsed: 2.542 sec
    [junit] Testsuite: test.mx.uam.ingsoft.pluginadmin.AdministradorPluginsImplTest
    [junit] Tests run: 7, Failures: 0, Errors: 0, Time elapsed: 2.542 sec
    [junit] ------------- Standard Output ---------------

                          ....

    [junit] ------------- ---------------- ---------------
 
    [junit] Testcase: testAdministradorPluginsImpl took 0.03 sec
    [junit] Testcase: testGetListaPlugins took 0.01 sec
    [junit] Testcase: testGetPlugin took 0.067 sec
    [junit] Testcase: testInstalaPlugin took 0.03 sec
    [junit] Testcase: testRetiraPlugin took 0.024 sec
    [junit] Testcase: testActivaPlugin took 2.31 sec
    [junit] Testcase: testDesactivaPlugin took 0.056 sec
 
BUILD SUCCESSFUL
Total time: 5 seconds



Paso 2:

Checa la case test.mx.uam.ingsoft.pluginadmin.AdministradorPluginsImplTest y comparala con la clase que está probando: mx.uam.ingsoft.pluginadmin.AdministradorPluginsImpl

Paso 3:

Para probar el administrador de plugins, es necesario instalar un plug-in. Sin embargo, si recuerdas, al ser inicializado, un plug-in recibe un Contexto. Dentro de la arquitectura, el contexto está implementado por el núcleo de la aplicación, así que no es factible instanciar toda la aplicación para hacer las pruebas. Por ello es necesario crear unos stubs que implementen por un lado el contexto y por el otro la interfaz de usuario, que es accesible desde la interfaz contexto.
  1. Examina los stubs que se encuentran en el package test.mx.uam.ingsoft.stub
  2. En que pruebas se usan instancias de estos stubs?

Paso 4:

Como podrás observar, la realización de pruebas es automática y se realiza desde ant. Entra al archivo build.xml y busca el target test para que veas como se realiza esto.
Enseguida modifica el archivo build.xml para que el target test quede como sigue:

Dentro de target init:

<property name="junitreports.dir" value="${doc.dir}/junitreports"/>
Dentro de target prepare:
<mkdir dir="${junitreports.dir}"/>
Dentro de target clean:
<delete dir="${junitreports.dir}"/>
<target name="test" depends="compile">
    <junit printsummary="true" >
        <formatter type="xml"/>
        <test name="${maintestclass}"/>
        <classpath>
            <pathelement location="${build.dir}" />
        </classpath>
    </junit>
    <junitreport todir="${junitreports.dir}">
        <fileset dir=".">
                <include name="TEST-*.xml"/>
        </fileset>
        <report format="frames" todir="${junitreports.dir}/html"/>
    </junitreport>
</target>

Ejecuta el target test y ahora apunta tu navegador al directorio doc/junitreports/html

Ejercicio 3: Clase de pruebas para plugins

Ahora que tienes la versión más actual de la arquitectura, ve al package de las interfases (comun) y analiza la interfase Plugin. Como podrás observar, se ha añadido un nuevo metodo: getConfigurador(). Este metodo permite a un plugin proveer un objeto que facilita su configuración en tiempo de ejecución. El configurador es un objeto que sigue las convenciones getter y setter que vimos en clase. Si estudias la documentación de la interfase, verás que el plug-in no debe regresar ningun configurador si aun no está inicializado.

A hacer:

Basandote en lo que se vio en los dos primeros ejercicios, modifica tu proyecto de plugins para que incluya un target de prueba de tu plug-in. Los pasos a seguir son:
  1. Crear un package de pruebas
  2. Crear una clase de prueba (puedes dejar que eclipse te ayude con esto)
  3. Retormar los stubs del ejercicio anterior y reutilizarlos
  4. Incluir un target en ant para que se realicen las pruebas y ponga la salida en formato HTML
  5. Lanzar las pruebas.


Ultima actualización: 16 Febrero 2005
contacto: hcm@xanum.uam.mx
Homepage