viernes, 19 de julio de 2013

TUTORIAL TESTNG: FRAMEWORK PARA TUS TESTS

TestNG (Next Generation) es un framework de testing inspirado en JUnit y NUnit pero introduciendo nuevas caractarísticas como los test de dependencia y el concepto de grouping. Su uso nos permite realizar todas las categorías de test como pruebas unitarias, de integración, end-to-end, pruebas funcionales, etc...





Instalación en Eclipse

Instalar el plugin de TestNG para Eclipse es sencillo. En mi caso es Eclipse JUNO y únicamente para instalarlo lo único que tenemos que hacer es buscarlo con la herramienta Eclipse MarketPlace y pulsar el botón de Install.



Crear una clase para nuestros test con TestNG es igualmente sencillo. En nuestro proyecto creamos una nueva clase TestNG. Pulsamos NEXT y después seleccionamos las anotaciones que deseamos que aparezcan en nuestra clase:



Cuando creamos nuestra clase TestNG nos dará fallos en las anotaciones. Esto es porque debemos incluir en nuestro proyecto las librerías del framework. Para ello pulsamos sobre las Properties de nuestro proyecto y en Java Build Path añadimos la librería de TestNG.


Ejemplo con anotaciones básicas

A continuación repasamos las anotaciones básicas y un ejemplo con su resultado:

  • @BeforeClass. Código ejecutado antes de ejecutar los test. Aquí se podría inicializar por ejemplo alguna fuente de datos para utilizarla en nuestros test.
  • @AfterClass. Código ejecutado después de ejecutar todos nuestros test. Aquí se podrían cerrar todos los recursos que hemos abierto en el código bajo la etiqueta @BeforeClass.
  • @BeforeMethod. Código ejecutado antes de cada test.
  • @AfterMethod. Código ejecutado después de cada test.
  • @Test. Indica que el método es un test.

Un ejemplo:

package es.jpascu.testng;

import java.util.ArrayList;
import java.util.Collection;

import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class TestNGBasic {
 private Collection collection;

 @BeforeClass
 public void oneTimeSetUp() {
  // one-time initialization code
  System.out.println("@BeforeClass - oneTimeSetUp");
 }

 @AfterClass
 public void oneTimeTearDown() {
  // one-time cleanup code
  System.out.println("@AfterClass - oneTimeTearDown");
 }

 @BeforeMethod
 public void setUp() {
  collection = new ArrayList();
  System.out.println("@BeforeMethod - setUp");
 }

 @AfterMethod
 public void tearDown() {
  collection.clear();
  System.out.println("@AfterMethod - tearDown");
 }

 @Test
 public void testEmptyCollection() {
  Assert.assertEquals(collection.isEmpty(), true);
  System.out.println("@Test - testEmptyCollection");
 }

 @Test
 public void testOneItemCollection() {
  collection.add("itemA");
  Assert.assertEquals(collection.size(), 1);
  System.out.println("@Test - testOneItemCollection");
 }

}

Ejemplo con características avanzadas

En este ejemplo añadimos otros ejemplos de características avanzadas que se se pueden utilizar en nuestros tests con TestNG:

  • @Test(expectedExceptions=TipoException.class). El test unitario pasa aunque en el test se lanza la excepción de tipo TipoException.class.
  • @Test(enabled=false). El test unitario no se ejecuta.
  • @Test(timeout=1000). Si tarda más de 1 segundo el test unitario pasará como FAILED, pero nos aseguramos que finalice su ejecución.
Un ejemplo:




package es.jpascu.testng;

import org.testng.annotations.Test;

public class TestNGAdvanced {

 @Test(expectedExceptions = NullPointerException.class)
 public void testException() {
  String s = null;
  s.charAt(0);
 }

 @Test(enabled = false)
 public void testIgnore() {
  System.out.println("Esto no se ejecuta!!");
 }

 @Test(timeOut = 1000)
 public void testBucleInfinito() {
  while (true)
   ;
 }

}

Ejemplo con parámetros básicos y complejos

Podemos definir una suite, que es un XML en el que entre otras cosas se pueden definir varios clases de test que se ejecuten juntas. Además podemos definir parámetros simples (int, float) como objetos complejos (ArrayList, String, etc..).


Primero vemos un ejemplo en el que se define un parámetro de tipo int en el suite.xml que estará disponible en la ejecución de nuestras clases de test. Para definirlo en nuestro test se emplea la anotacion @Parameters.


package es.jpascu.testng;

import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class TestNGBasicParameter {
  @Test
  @Parameters(value="number")
  public void testWithBasicParameter(int number) {
   System.out.println("El valor del paámetro es: " + number);
  }
}


  
     
 
    
       
    
   
 
Ahora vemos como TestNG gestiona el paso de parámetros complejos. Para ello se utiliza la anotación @DataProvider. En el ejemplo vemos como se pasan tipos complejos como colecciones.



package es.jpascu.testng;

import java.util.ArrayList;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class TestNGComplexParameter_1 {
 @Test(dataProvider = "dp")
 public void parameterArrayListInTest(ArrayList list) {
    System.out.println("Primer Elemento Lista : " + list.get(0));
    System.out.println("Segundo Elemento Lista : " + list.get(1));
 }
 
 //This function will provide the parameter data
 @DataProvider(name = "dp")
 public Object[][] parameterIntTestProvider() {
  ArrayList lista = new ArrayList();
  lista.add("1");
  lista.add("2");
  return new Object[][]{
    
     {lista}
        };
 }
}


En este otro ejemplo vemos como se pasa un POJO como parámetro:


package es.jpascu.testng;

public class Pojo {
 private int numero;
 
 private String mensaje;

 public Pojo(int numero, String mensaje) {
  super();
  this.numero = numero;
  this.mensaje = mensaje;
 }

 public int getNumero() {
  return numero;
 }

 public void setNumero(int numero) {
  this.numero = numero;
 }

 public String getMensaje() {
  return mensaje;
 }

 public void setMensaje(String mensaje) {
  this.mensaje = mensaje;
 }
 
 
}

package es.jpascu.testng;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class TestNGPojoParameter_1 {
 @Test(dataProvider = "dp")
 public void parameterPojoListInTest(Pojo obj) {
    System.out.println("Pojo - numero : " + obj.getNumero());
    System.out.println("Pojo - mensaje : " + obj.getMensaje());
 }
 
 //This function will provide the parameter data
 @DataProvider(name = "dp")
 public Object[][] parameterPojoTestProvider() {
  Pojo pojo = new Pojo(1, "Hola");
  
  return new Object[][]{
    
     {pojo}
        };
 }
}

Concepto de grouping

En este apartado vemos un ejemplo del concepto de grouping que no existe en JUnit 4. Por ejemplo, imaginemos que tenemos una clase de test en la que probamos operaciones a LDAP y a bases de datos. Podemos ejecutar los test agrupados por su funcionalidad, en nuestro caso, LDAP y BBDD. Si queremos ejecutar sólo los test relacionados con LDAP haríamos lo siguiente:


package es.jpascu.testng;

import org.testng.annotations.Test;

public class TestConnection {

 @Test(groups="ldap")
 public void testLDAP_OP1() {
  System.out.println("Method - testLDAP_OP1");
 }

 @Test(groups="ldap")
 public void testLDAP_OP2() {
  System.out.println("Method - testLDAP_OP1");
 }

 @Test(groups="bbdd")
 public void testBBDD_Oracle() {
  System.out.println("Method - testBBDD_Oracle");
 }

 @Test(groups="bbdd")
 public void testBBDD_SQLServer() {
  System.out.println("Method - testBBDD_SQLServer");
 }
}



      
        
      
    
    
        
    
  


Test Dependientes

Otro concepto que añade TestNG son los  test dependientes. Podemos definir en nuestras clases de test que un método de test determinado dependa de uno o varios métodos de test. Para ello utlizamos el atributo dependsOnMethod.


Aquí os pongo un ejemplo en el que nuestro testA depende del testB y el testC.


package es.jpascu.testng;

import org.testng.annotations.Test;

public class TestNGDepends {

 @Test(dependsOnMethods={"testB","testC"})
 public void testA() {
  System.out.println("testA");
 }

 @Test
 public void testB() {
  System.out.println("testB");
 }

 @Test
 public void testC() {
  System.out.println("testC");
 }

}

Conclusiones. JUnit4 vs TestNG.

Por último os pongo una tabla comparativa entre JUnit4 y TestNG para observar la funcionalidad que cubre cada uno de los dos frameworks:



TestNG es superior en los test de grupo, en parametrización de objetos complejos y en los test de dependencia además de cubrir todas las funcionalidades de JUnit 4

Otro punto a su favor es que para ejecutar varios ficheros de test juntos (Suite Test) se realiza mediante la definición de un fichero XML y no mediante anotaciones en una clase Java como se hace en JUnit 4. Además se puede integrar perfectamente con herramientas tan utilizadas como Maven o Selenium. 

En general se puede recomendar la utilización de este framework en lugar de JUnit 4 ya que cubre toda la funcionalidad de este último, es más flexible y añade nuevas capacidades.

Salu2.

Fuente: mkyong

No hay comentarios:

Publicar un comentario en la entrada