2 / 44www.4linux.com.br
Experiência em missão crítica de missão crítica
Pioneira no ensino de Linux à distância
Parceira de treinamento IBM
Primeira com LPI no Brasil
+ de 30.000 alunos satisfeitos
Reconhecimento internacional
Inovação com Hackerteen e Boteconet
Testes em aplicações JEE:Testes em aplicações JEE: Montando sua infra de testes automatizadosMontando sua infra de testes automatizados
4 / 44www.4linux.com.br
AgendaAgenda
● Porque testar?● Escrevendo testes com mais valor● Problemas testando componentes JEE● Como integrar containers aos testes.
5 / 44www.4linux.com.br
Porque automatizar testes?Porque automatizar testes?
● Modinha...● Eficiência dos testes de regressão
● Você pode melhorar/refatorar o sistema com tranquilidade, se estragar você sabe instantaneamente que estragou
● Integração contínua pode te tirar do apuro● Você tem uma espécie de auditoria “vigiando” o funcionamento do
seu código, se falhar você saberá exatamente onde e porque falhou
6 / 44www.4linux.com.br
Problemas na hora de testar?Problemas na hora de testar?
● Mas te ensinaram como usar em situações do cotidiano?● Até que ponto testar com objetos fake e mocks?
● Difícil montar ambientes onde os testes podem ser executados
● O quanto de esforço é necessário para executar testes em ferramentas de build e IDEs ao mesmo tempo.
Segundo Bill Burke, mocks te dão uma falsa sensação de segurança, pois permitem distorcer os testes para que seu código passe.
7 / 44www.4linux.com.br
Problemas em testes de Problemas em testes de componentes JEEcomponentes JEE
● Ciclo chato de desenvolvimento
● Isolar o que deve ser testado● Para um componente ser testado, ele dependente de um
outro componente ou um serviço oferecidos pelo container.
● Exemplos:– Filas de mensageria– Transacionalidade– Segurança– Data Sources
Implementação Deploy Test Implementação
8 / 44www.4linux.com.br
Mas eu utilizo Ant e o Maven para executar os testes pra mim, moleza!
Ciclo chato de desenvolvimento
9 / 44www.4linux.com.br
Utilizando ferramentas de Utilizando ferramentas de buildbuild
● Ant, Maven:● Vantagem:
– Fácil de executar testes: mvn test (unitários) / mvn verify (unitários e integração)
– Fácil integração com servidor de integração contínua como Jenkins.
● Desvantagem:– Executa todos os testes de um vez. – (Maven) Os erros são somente mostrados nos
relátorios gerados– (Maven) não integra as suas fases de teste com a
IDE
10 / 44www.4linux.com.br
Vei, na boa! Minha aplicação nem usa EJB
11 / 44www.4linux.com.br
Para recursos simples da WebPara recursos simples da Web
● Sua aplicação não usa EJB, JTA, JMS?● Você não precisa testar em um servidor de aplicações FULL. ● Utilize só um container web, mais leve e mais fácil de
configurar.● Opções como o Jetty, Tomcat. Ambos possuem versão
embutidas, que pode ser adicionada aos testes.● Jetty é dividido em módulos e permite especificar quais deles
seram iniciaram com os testes.● Possuem plugins para Maven.● Possuem APIs que podem ser usadas dentro dos testes.
12 / 44www.4linux.com.br
Embedded JettyEmbedded Jetty
● Container de servlets leve● Possui uma API para configurar e iniciar
uma instância do container.
Server server = new Server(8080);Context root = new Context(server,"/agenda",Context.SESSIONS);
root.addServlet(new ServletHolder(new ContatoServlet()), "contatos");server.start();
13 / 44www.4linux.com.br
API do JettyAPI do Jetty
private static WebAppContext gerandoContextoAplicacao() throws Exception {WebAppContext context = new WebAppContext();context.setWar(new File(URI_DO_WAR).getAbsolutePath());context.setContextPath(“/aplicacao-do-jjustjava/”);
context.setConfigurations(new Configuration[] {new AnnotationConfiguration(), new JettyWebXmlConfiguration(),new WebInfConfiguration(), new WebXmlConfiguration(),new TagLibConfiguration(), new MetaInfConfiguration(),new PlusConfiguration(), new FragmentConfiguration(),new EnvConfiguration() });
return context;}
@BeforeClasspublic static void inicializar() throws Exception {
server = new Server(SERVER_PORT);WebAppContext contexto = gerandoContextoAplicacao();
server.setHandler(contexto);server.start();
}
A API do Jetty permite que você especifique os módulos que são importantes para você, no caso, em seus testes.
Mais dependências para utilizar JSPs: ● ant-1.6.5.jar● core-3.1.1.jar● jsp-2.1.jar● jsp-api-2.1.jar
14 / 44www.4linux.com.br
Tomcat EmbeddedTomcat Embedded
● Mais fácil de iniciar que o Jetty por todos os módulos já virem configurados para iniciar.
// Configura container de servlet embutidoTomcat servidor = new Tomcat();
// Aponta o diretorio temporario para que o container necessitaservidor.setBaseDir("target/temp");
// Especifica a porta onde irá funcionarservidor.setPort(8081);
// Inicia servidorservidor.start();
<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>7.0.27</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>7.0.27</version> <scope>test</scope> </dependency>
15 / 44www.4linux.com.br
API do Tomcat : Adicionando API do Tomcat : Adicionando ConteúdoConteúdo
servidor.addWebapp("/carrinho", enderecoDoWar); Adiciona o WAR ao contexto /carrinho
File diretorioWebapp = new File("src/main/webapp");Context contexto = servidor.addWebapp("/", diretorioWebapp.getAbsolutePath());
servidor.addServlet("/", "LeilaoServlet", new LeilaoServlet());contexto.addServletMapping("/leilao", "LeilaoServlet");
Mapeando o Servlet adicionado
Você pode associar um WAR do file system a um contexto utilizando o método addWebapp
Também é possível tornar um diretório, o contexto da aplicação, adicionando servlets aoContainer e mapeando-os no contexto.
16 / 44www.4linux.com.br
Mas os como eu forneço pacotes com as classes para os containers dentro dos meus testes?
17 / 44www.4linux.com.br
JBoss ShrinkWrapJBoss ShrinkWrap
● Projeto que ajuda automatizar e personalizar a criação de pacotes Java
● EAR, WAR, JAR ou também qualquer outro Zip.● A maioria dos container embutidos permitem especificar um
pacote para registrado inserido em um contexto.
WebArchive warAplicacao = ShrinkWrap.create(WebArchive.class, “livraria.war”).addClasses(Cliente.class, CartaoCreditoInfo.class).addPackage(“fourlinux.justjava.store.dao”);.setWebXML(“/src/test/resources/web.xml”);
18 / 44www.4linux.com.br
JBoss ShrinkWrapJBoss ShrinkWrap
<project> ... <dependencies> ... <dependency> <groupId>org.jboss.shrinkwrap</groupId> <artifactId>shrinkwrap-api</artifactId> </dependency> <dependency> <groupId>org.jboss.shrinkwrap</groupId> <artifactId>shrinkwrap-impl-base</artifactId> <scope>test</scope> </dependency> ... </dependencies> ... </project>
<repository> <id>jboss-public-repository-group</id> <name>JBoss Public Maven Repository Group</name> <url>https://repository.jboss.org/nexus/content/groups/public/</url> </repository>
19 / 44www.4linux.com.br
Usando o ShrinkWrapUsando o ShrinkWrap
// Exportando WAR:WebArchive war = ShrinkWrap.create(WebArchive.class);
war.addPackages(true, "fourlinux.justjava");
war.as(ZipExporter.class).exportTo(new File(“/target/shrinkwrap/aplicacao.war”));
Adiciona todas as classesdo seguinte pacote recursivamente
Cria um arquivo zip para o conteúdo indicado
// Embedded Jetty WebAppContext context = new WebAppContext();context.setWar(new File(uriDoWar).getAbsolutePath());;
20 / 44www.4linux.com.br
Usando ShrinkWrap + MavenUsando ShrinkWrap + Maven
● As vezes seu projeto está dividido em submódulos e um componente que está sendo testado depende de um módulo declarado no POM
● Ou você precisa adicionar um driver JDBC no pacote para testar
ShrinkWrap ResolverMavenDependencyResolver resolver = DependencyResolvers.use(
MavenDependencyResolver.class);
MavenDependencyBuilder dominio = resolver.artifact("soujava.justjava:livraria-dominio:1.0");
carrinho.addAsLibraries(dominio.resolveAs(GenericArchive.class));
21 / 44www.4linux.com.br
MAS MEU PROJETO POSSUI EJBs, COMO TESTO?
22 / 44www.4linux.com.br
Apache OpenEJBApache OpenEJB
● Container EJB● Desde 1999● Como pode ser utilizado nos testes?
● Diferencial: Leve e rápido● Pode ser iniciado dentro dos testes.● Suporta as versões 3.1, 3.0, 2.1, 2.0, 1.1● Simples configuração e inicialização.● Simplicica os ciclos de desenvolvimento e teste.
23 / 44www.4linux.com.br
Configurando OpenEJB com Configurando OpenEJB com MavenMaven
● É utilizado como uma simples dependência.<project>
...<dependency>
<groupId>org.apache.openejb</groupId><artifactId>javaee-api</artifactId><scope>provided</scope><version>6.0-3-SNAPSHOT</version>
</dependency><dependency>
<groupId>org.apache.openejb</groupId><artifactId>openejb-core</artifactId><scope>test</scope><version>4.0.0-beta-1</version>
</dependency></project>
API
Container
<dependency><groupId>org.apache.openejb</groupId><artifactId>openejb-core-hibernate</artifactId><version>4.0.0-beta-1</version><type>pom</type>
</dependency>
Preciso de suporte a JPA, o que faço?
OpenEJB com Hibernate
24 / 44www.4linux.com.br
Iniciando container Iniciando container
● O container pode ser iniciado dentro dos testes, seja a cada teste ou em um setup para todos os testes.
@Beforepublic void inicializacao() {
Properties props = new Properties();props.put(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.openejb.client.LocalInitialContextFactory");Context context = new InitialContext(props);
}
@Beforepublic void inicializacao() {
EjbContainer container = EjbContainer.createEjbContainer();Context context = container.getContext();
}
<= EJB 3.0
>= EJB 3.1
25 / 44www.4linux.com.br
Testando SessionBeansTestando SessionBeans
@Statelesspublic class ServicoPagamento {
public void cobrar(double valor, CartaoCreditoInfo ccInfo) {...
}}@Testpublic class ServiceoPagamentoIT {
@Test(expected=IllegalArgumentException.class)public void valorNegativoLancaExcecao() {
Context contexto = EjbContainer.createEjbContainer().getContext();ServicoPagamento sp = (ServicoPagamento)
contexto.lookup(“java:global/projeto/ServicoPagamento”);sp.cobrar(-5, ccInfo);
}} Utilizando o JNDI para recuperar componentes
como session beans
Provê um JNDI padrãoque você pode customizá-lo.
O OpenEJB caça sua aplicação por componentes JavaEE que podem ser de sua responsabilidade.
26 / 44www.4linux.com.br
Configurando RecursosConfigurando Recursos
public class OrderProcessorIT {@Testpublic void processOrderAddItensToDatabase() {
Properties props = new Properties(); props.put("shopDatabase", "new://Resource?type=DataSource"); props.put("shopDatabase.JdbcDriver", "org.hsqldb.jdbcDriver"); props.put("shopDatabase.JdbcUrl", "jdbc:hsqldb:mem:shopdb");
Context contexto = EjbContainer.createEjbContainer(props).getContext();OrderProcessor orders = (OrderProcessor)
contexto.lookup(“java:global/projeto/OrderProcessor”);}
}
@Statelesspublic class OrderProcessor {
@ResourceDataSource dataSource;
...}
Configurando recursos como DataSource, filas, tópicos, fábricas de conexões...
27 / 44www.4linux.com.br
Ligando o teste no containerLigando o teste no container
● Há momentos onde é mais pratico permitir que o teste tenha acesso aos recursos através de injeção de dependência.public class GameContextIT {
@PersistenceContext(unitName=”gameunit”)private EntityManager em;
@Resourceprivate Queue filaJogadores;
@EJBGameController controller;…public SetUp() throws Exception {
EJBContainer container = EJBContainer.createEJBContainer();container.getContext().bind(“inject”, this);
}}
Acesso a todos os recursos do Container, como filas, datasources, ejbs e ao contexto cdi
28 / 44www.4linux.com.br
Mais eu quero testar em um servidor de aplicação
completo, inútil!
29 / 44www.4linux.com.br
Testando na real com Testando na real com JBoss ArquillianJBoss Arquillian
● Facilmente extensível.● Ajuda a diminui o esforço para fazer testes em qualquer
tipo de container, seja remoto ou embutido.● Gerencia todo o ciclo de vida do container e da aplicação
sendo executada nele.● Com ajuda do ShrinkWrap, permite montar pacotes
personalizados para deploy.● Permite executar testes dentro e fora do container.
30 / 44www.4linux.com.br
Arquillian + MavenArquillian + Maven
Novamente adicionar repositório Jboss:http://repository.jboss.org/nexus/content/groups/public
<dependency><groupId>org.jboss.arquillian</groupId><artifactId>arquillian-bom</artifactId><version>1.0.0.Final</version><scope>import</scope><type>pom</type>
</dependency>
Importando dependências do Arquillian
<dependency><groupId>org.jboss.arquillian.junit</groupId><artifactId>arquillian-junit-container</artifactId><version>1.0.0.Final</version>
</dependency>
Integração com Junit ou TestNG
Falta a extensão do container...
31 / 44www.4linux.com.br
Arquillian + MavenArquillian + Maven
Extensões para
● JBoss● Tomcat● Glassfish● Resin● Weld● OSGI● CloudBees● OpenEJB● Jetty● Google AppEngine● Spring
Arquillian com Glassfish<dependency>
<groupId>org.jboss.arquillian.container</groupId><artifactId>arquillian-glassfish-embedded-3.1</artifactId><version>1.0.0.CR3</version><scope>test</scope>
</dependency><dependency>
<groupId>org.glassfish.main.extras</groupId><artifactId>glassfish-embedded-all</artifactId><version>3.1.2</version><scope>test</scope>
</dependency>
Glassfish Embutido
Extensão para glassfish
32 / 44www.4linux.com.br
JBoss ArquillianJBoss Arquillian
● Do que o Arquillian precisa?● Os testes devem funcionar com
@RunWith(Arquillian.class)● Pelo menos um método anotado com
@Test● Um método estático que entregue um pacote Java montado
pelo ShrinkWrap● Um container onde ele irá instalar o pacote.
33 / 44www.4linux.com.br
Teste com CDI usando Teste com CDI usando ArquillianArquillian@RunWith(Arquillian.class)public class GerenciadorReservasTest {
@Injectprivate GerenciadorReservas reservas;
@Deploymentpublic static JavaArchive gerandoArquivoDeploy() {
JavaArchive arquivo = ShrinkWrap.create(JavaArchive.class);arquivo.addPackages(true, “fourlinux.justjava”);arquivo.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");return arquivo;
}
@Testpublic void reservaDeveGerarCobranca() throws Exception {
Cabine cabine = new Cabine(“Titanic”, “A12”, Tipo.LUXO, 340.00f);Usuario usuario = new Usuario("[email protected]", "Gabriel Ozeas");
Cobranca cobranca = reservas.reservarCabine(new Cabine[]{cabine}, usuario);assertEquals(new Float(340), new Float(cobranca.getValor()));
}}
34 / 44www.4linux.com.br
Testando em Containers Testando em Containers RemotosRemotos
<dependency><groupId>org.jboss.as</groupId><artifactId>jboss-as-arquillian-container-remote</artifactId><version>7.1.1.Final</version><scope>test</scope>
</dependency><dependency>
<groupId>org.jboss.as</groupId><artifactId>jboss-as-controller-client</artifactId><version>7.1.1.Final</version><scope>test</scope>
</dependency>
Cliente JBoss Remoto
Utilizando containers remotos e gerenciados, faz com que eles iniciem em outra JVM, ou seja os logs e debug não estão disponiveis na JVM que iniciou os testes.
35 / 44www.4linux.com.br
Arquillian como ClienteArquillian como Cliente
@RunWith(Arquillian.class)public class GerenciadorReservasTest {
@Deployment(testable = false)public static JavaArchive gerandoArquivoDeploy() {
JavaArchive arquivo = ShrinkWrap.create(JavaArchive.class);arquivo.addPackages(true, “fourlinux.justjava”);arquivo.setWebXML(“src/main/webapp/WEB-INF/web.xml”);return arquivo;
}
@Testpublic void verificandoTotalItensInicial() throws Exception {
WebDriver navegador = new HtmlUnitDriver();navegador.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
navegador.get("http://localhost:8081/leilao");WebElement body = navegador.findElement(By.tagName("h1"));assertEquals("Histórico do item", body.getText());
}}
Testando UI com Selenium
Deploy no container, mas testa no cliente
Teste OUT Container
36 / 44www.4linux.com.br
Misturando In e Out ContainerMisturando In e Out Container
@RunWith(Arquillian.class)public class GerenciadorReservasTest {
@Injectprivate GerenciadorReservas reservas;
@Deploymentpublic static JavaArchive gerandoArquivoDeploy() {
JavaArchive arquivo = ShrinkWrap.create(JavaArchive.class);arquivo.addClasses(...);...
}
@Testpublic void reservaDeveGerarCobranca() throws Exception {
….Cobranca cobranca = reservas.reservarCabine(new Cabine[]{cabine}, usuario);assertEquals(new Float(340), new Float(cobranca.getValor()));
}
@Test@RunAsClientpublic void verificandoTotalItensInicial() throws Exception {
WebDriver navegador = new HtmlUnitDriver();navegador.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);...
}}
Teste será executado na JVM que inicou os testes
Teste será executado na JVM do container
37 / 44www.4linux.com.br
PLUS: InfinitestPLUS: Infinitest
● Customizando a IDE:● Teste continuo com Infinitest
– Ajuda a executar os testes dentro do Eclipse automaticamente– Verde, passou, Vermelho Falhou.– Permite criar filtros para escolher quais testes serão sempre
executados.– Recomendado para executar em testes de unidade, pois são
normalmente executados em millisegundos.
Testes que falharam
38 / 44www.4linux.com.br
Filtrando testes no InfinitestFiltrando testes no Infinitest
● O Infinitest permite que você filtre os testes que serão executados continuamente.
● Arquivo infinitest.filtersBloqueia todos os testes de integração:.*ITest
Bloqueia todos os testes de um pacote:org\.soujava\.justjava\..*
Bloqueia todos os teste do projeto:.*
39 / 44www.4linux.com.br
EmmaEmma
40 / 44www.4linux.com.br
EmmaEmma
41 / 44www.4linux.com.br
Cobertura dos TestesCobertura dos Testes
42 / 44www.4linux.com.br
Cobertura dos TestesCobertura dos Testes
43 / 44www.4linux.com.br
Chegaremos a 100% ???Chegaremos a 100% ???
➢ Nem tudo será testado➢ Ex: Gets e Setters!➢ Classes sem lógica de negócio /
domínio➢ O aumento do esforço para se chegar
a 100% pode não valer a pena!
44 / 44www.4linux.com.br
O que acontece na realidade?O que acontece na realidade?
➢ A maioria das empresas estabelece um patamar mínimo aceitável:➢ Ex. 80% de cobertura (somente um exemplo)!
➢ Os testes unitários e a verificação de cobertura são feitos automaticamente;➢ A verificação de cobertura pode ser configurada
para analisar apenas algumas classes ou pacotes ➢ Utilizar patamares diferentes para recusar o build
em cada classe ou pacote.
Top Related