Pruebas unitarias con Arquillian.
Las pruebas unitarias son muy necesarias en el desarrollo de software, ya que nos permiten validar la funcionalidad de los métodos y corregir con anticipación algun error que estos presenten, en el mundo JAVA, estas pruebas unitarias se las lleva a cabo mediante JUNIT.
Pero cuando necesitamos realizar una bateria de pruebas más completa y compleja aparece Arquillian al rescate, y gracias a esta plataforma de Tests podemos lanzar nuestras pruebas con JUNIT o TESTNG, las dos librerias más usadas en la actualidad para pruebas unitarias. Arquillian enriquece la clase del test con servicios como:
- Inyeccion.
- Contexto
Algunos de los tipos de inyeccion que soporta Arquillian en entornos Java JEE son.
- @Inject
- @Resource
- @EJB
- @PersistenceUnit, @PersistenceContext
La clase del test no hace referencia al contenedor en específico, esto quiere decir que el mismo test lo podemos validar contra varios tipos de contenedores y con esto no estamos atados a un contenedor específico.
Arquillian permite usar el contenedor de tres formas distitnas.
- Remote container: Siginifica que el contenedor reside en una JVM separada donde se va a correr el test, Arquillian se encarga de vincular la clase test para deployar en el contenedor remoto.
- Managed container: Es similar al Remote container con la excepcion que el inicio y parado del contenedor lo realiza Arquillian.
- Embedded container: Este contenedor reside en la misma JVM.
Para empezar a trabajar con Arquillian debemos agregar a nuestro archivo pom.xml de maven las siguientes librerias.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<version>1.4.1.Final</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
Esta dependencia nos permite administrar las versiones de las dependencias de Aquillian.
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
Integramos JUNIT para ejecutar nuestras pruebas unitarias.
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<version>1.1.11.Final</version>
<scope>test</scope>
</dependency>
Para integrar JUNIT con Arquillian
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-impl-maven</artifactId>
<scope>test</scope>
</dependency>
Permite la utilización de distintos tipos de contenedores.
<dependency>
<groupId>org.wildfly.arquillian</groupId>
<artifactId>wildfly-arquillian-container-managed</artifactId>
<version>2.0.1.Final</version>
<scope>test</scope>
</dependency>
Para nuestro ejemplo vamos a utilizar el contendor embebido de wildfly.
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Nos permite controlar los logs a nivel del contenedor.
Hay que tomar en cuenta que cuando creamos un proyecto vamos a tener el directorio donde se van a ubicar las clases y los recursos para nuestros tests, es decir.
- /src/test va a contener las clases para nuestros tests.
- /src/test/resources va a contener los recursos adicionales para ejecutar nuestros tests.
En el directorio /src/test/resources vamos a colocar el archivo arquillian.xml con la siguiente configuración, lo que le estamos indicando es las configuraciones del contenedor embebido.
<?xml version="1.0"?>
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://jboss.org/schema/arquillian"
xsi:schemaLocation="http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<defaultProtocol type="Servlet 3.0"/>
<container qualifier="jboss-managed" default="true">
<configuration>
<property name="jbossHome">/ruta/a/tu/home_del_contenedor</property>
<property name="javaHome">/ruta/a_tu_java_home/property>
<property name="managementAddress">localhost</property>
<property name="managementPort">9990</property>
<property name="username">admin</property>
<property name="password">password</property>
<property name="serverConfig">standalone.xml</property>
<property name="allowConnectingToRunningServer">true</property>
</configuration>
</container>
</arquillian>
En el mismo directorio vamos a ubicar el archivo test-persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="nombreUnidadPesistencia" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/nombreDS</jta-data-source>
</persistence-unit>
</persistence>
CLASES UTILIZADAS PARA LA PRUEBA.
Para el ejemplo utilizamos la siguiente entidad.
@Entity
@Table(name = "catalogs", schema = "sistema")
public class Catalogs {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "cata_id")
private Integer cataId;
@Column(name = "cata_order")
private Integer cataOrder;
@Column(name = "cata_text1")
private String cataText1;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 2147483647)
@Column(name = "cata_text2")
private String cataText2;
@Column(name = "cata_number")
private Integer cataNumber;
}
El servicio que utilizamos es el siguiente.
@LocalBean
@Stateless
public class CatalogsFacade extends AbstractFacade<Catalogs,Integer>{
public CatalogsFacade() {
super(Catalogs.class, Integer.class);
}
/**
* Carga todos los catalogos
* @return
* @throws Exception
*/
public List<Catalogs> buscaTodosCatalogos() throws Exception{
String sql="SELECT C FROM Catalogs C ORDER BY C.catalogsType.catyId,C.cataOrder";
Map<String, Object> camposCondicion=new HashMap<String, Object>();
return findByCreateQuery(sql, camposCondicion);
}
}
Nuestra clase CatalogsFacadeTest.java la vamos a ubicar en el directorio /src/tests
@RunWith(Arquillian.class)
public class CatalogsFacadeTest {
private static final Logger LOGGER = LoggerFactory.getLogger(CatalogsFacadeTest.class);
//invocamos al servicio
@EJB
private CatalogsFacade catalogsEjb;
@Deployment
public static WebArchive createDeployment(){
return ShrinkWrap.create(WebArchive.class,"CatalogsFacadeTest.war") //le indicamos que vamos a crear un archivo war para deployar en el servidor embebido
.addClass(CatalogsFacade.class) //hacemos referencia a la clase del servicio
.addClass(AbstractFacade.class) //CatalogsFacade hace referencia a la clase AbstractFacade, por lo tanto tambien debemos hacer referencia a ella
.addPackage(Projects.class.getPackage()) //En el caso de que necesitemos hacer referencia a otras clase podemos hacer referencia al paquete donde se encuentran las clases que necesitamos
.addPackage(ProjectsGenderInfo.class.getPackage())
.addPackage(GeographicalLocations.class.getPackage())
.addClass(DaoException.class)
.addAsResource("test-persistence.xml","META-INF/persistence.xml") // con esto le indicamos que nuestro archivo test-persistence.xml se agregue como recuros.
.addAsManifestResource(EmptyAsset.INSTANCE,"beans.xml");
}
@Test
public void testCatalogs(){
try{
Assert.assertTrue(catalogsEjb.buscaTodosCatalogos().size()>0);
LOGGER.info("CLASE: CatalogsFacade");
LOGGER.info("METODO: List<Catalogs> buscaTodosCatalogos()");
LOGGER.info("RETORNA: List<Catalogs>");
LOGGER.info("RESULTADO: EXITOSO");
}catch(Exception e){
e.printStackTrace();
}
}
}
Podemos ejecutar el test mediante el IDE, sea este Eclipse, NetBeans, etc. en cualquiera de los casos lo que vamos a obtener es un mensaje que nos indica que el servidor ejecuta la prueba unitaria con satisfaccion y en el caso de los logs, podremos visualizar los mensajes respectivos.
CONCLUSIONES.
- Arquillian nos permite ejecutar test a servicios, microservicios, etc.
- Arquillian nos permite ejecutar nuestros tests en diferentes contenedores.
- Arquillian es robusto como plataforma para los tests.
- Las pruebas unitarias siempre deben formar parte de nuestros desarrollos, para así garantizar la calidad de nuestro código.
Las pruebas unitarias es un tema que lo tratamos en nuestro curso JAVA de Enterprise Java Beans.