quarta-feira, 5 de outubro de 2011

Executando testes unitários com o framework Demoiselle


Primeiro, deve ser criado um projeto usando o arquétipo Vaadin do Framework Demoiselle.

Este vídeo feito pelo Cleverson (@zyc) pode ser usado como referência para a criação de uma aplicação que use o Demoiselle, com a diferença de que o arquétipo a ser utilizado é o do Vaadin.

Logo após a criação do projeto (aos 3:25 minutos do vídeo), podemos começar a modificar o mesmo.

Deve ser criado o pacote foo.init, na pasta src/main/java.

Dentro deste pacote deve ser criada a classe ApplicationLoader

package foo.init;

import javax.enterprise.context.ApplicationScoped;
import br.gov.frameworkdemoiselle.annotation.Shutdown;
import br.gov.frameworkdemoiselle.annotation.Startup;
import br.gov.frameworkdemoiselle.transaction.Transactional;

@ApplicationScoped
public class ApplicationLoader {

@Startup
@Transactional
public void load() {
}
@Shutdown
public void unload() {
}
}

No pacote foo, dentro da pasta src/test/java, deve ser criada a classe CategoryBCTest, a qual já conta com alguns testes:

package foo;

import static org.junit.Assert.assertNotNull;

import javax.inject.Inject;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import foo.business.CategoryBC;
import foo.domain.Category;
import foo.init.ApplicationLoader;

import br.gov.frameworkdemoiselle.transaction.Transactional;
import br.gov.frameworkdemoiselle.util.DemoiselleRunner;
import static org.junit.Assert.fail;

@Transactional
@RunWith(DemoiselleRunner.class)
public class CategoryBCTest {

@Inject
private ApplicationLoader appLoader;

@Inject
CategoryBC bc;

@Before
public void before() {
for (Category category : bc.findAll()) {
bc.delete(category.getId());
}
}

@Test
public void testInsert() {
Category category = getMinimalValidCategory();
bc.insert(category);
assertNotNull(category.getId());
}

@Test
public void testUpdate() {
Category category = getMinimalValidCategory();
bc.insert(category);

bc.update(category);
category = bc.load(category.getId());
}

@Test
public void testDelete() {
Category category = getMinimalValidCategory();
bc.insert(category);
category = bc.load(category.getId());
bc.delete(category.getId());
category = bc.load(category.getId());
Assert.assertNull(category);
}

@Test
public void testInsertLogradouroNull() {
Category category = getMinimalValidCategory();
category.setDescription(null);
try {
bc.insert(category);
}catch (javax.validation.ConstraintViolationException e) {
return;
}

fail("Aceitou inserção sem Descrição");
}

/**
* Este método retorna um objeto que é minimamente válido.
* @return Objeto mínimo possível
*/

public Category getMinimalValidCategory() {
Category cat = new Category();
cat.setDescription("Descrição");
return cat;
}

}

Ao se tentar executar o teste neste momento, é lançado o seguinte erro: java.lang.ClassFormatError: Absent Code attribute in method...

Isto ocorre porque o arquétipo disponibilzado vem com a dependência javaee-api e javaee-web-api, que especificam o JavaEE6.
No entanto, estas bibliotecas servem apenas para compilação, pois os métodos que estão dentro destes jars estão sem implementação.

Para corrigir este problema, deve ser feita a adição dos seguintes campos no arquivo pom.xml do projeto, os quais resolvem as dependências relativas a uma implementação completa do javaee 6.0:
<repository>
<id>repository.jboss.org</id>
<name>JBoss Repository</name>
<url>http://repository.jboss.org/nexus/content/groups/public-jboss/</url>
</repository>

<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>1.0.0.Final</version>
<scope>test</scope>
<type>pom</type>
</dependency>

Neste ponto, o JUnit teste ainda não consegue executar o teste (é lançada uma exceção do tipo java.util.NoSuchElementException, provavelmente ligada à falta de uma fonte/conexão a um banco de dados).

Resta agora configurar o acesso ao banco de dados:

O conteúdo da pasta src/main/resources deve ser copiado para a pasta src/test/resources

Na pasta src/main/resources/META-INF
Arquivo beans.xml:

<?xml version="1.0"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_1.xsd">

<alternatives>
<class>br.gov.frameworkdemoiselle.transaction.JPATransaction</class>
</alternatives>

</beans>

Arquivo persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

<persistence-unit name="bookmark-ds" transaction-type="RESOURCE_LOCAL">
<class>foo.domain.Bookmark</class>
<class>foo.domain.Category</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:hsql://localhost:9001/bookmark" />

<property name="eclipselink.logging.level" value="FINE" />
<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />

<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
</persistence-unit>
</persistence>

Na pasta src/test/resources/META-INF
Arquivo beans.xml:

<?xml version="1.0"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_1.xsd">
</beans>

Arquivo persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

<persistence-unit name="bookmark-ds">
<jta-data-source>java:/DefaultDS</jta-data-source>
<class>foo.domain.Bookmark</class>
<class>foo.domain.Category</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:hsql://localhost:9001/bookmark" />

<property name="eclipselink.logging.level" value="FINE" />
<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />

<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
</persistence-unit>
</persistence>

Com isto, chegamos à tão desejada barra verde do JUnit, juntamente com o deploy do projeto no JBOSS6.

Agradeço ao @mariojp pelo apoio na hora de encontrar esta solução, ao mostrar seu conhecimento sobre os arquivos de configuração.

3 comentários:

  1. Duas pessoas que admiro e tenho muito orgulho de chamar de amigos.
    Você e Cleverson, são proprietários de inteligência lógica fora do comum.

    Parabéns!

    ResponderExcluir
  2. O mérito desse post é de André Monteiro!

    Concordo com voce ZyC e voce são os caras. Eu estou correndo atras de voces :)

    []'s
    Grande amigo

    E parabéns pelo post Andre!!

    ResponderExcluir
  3. Velho, post muito bom. estou fazendo curso na impacta e cai no seu blog sem qurer... Cara, animal!

    Não sei se conhece a impacta, peço permissão pra deixar o link pra galera que eh afim do curso: http://www.impacta.com.br/treinamento/Excel-2010-Modulo-I.php

    ResponderExcluir