Categoria: Java
Fazendo Mocks com DAO Mockito
Olá Pessoal,
O post de hoje veremos como usar Mockito para coberir classes e metodos DAO. Eu particularmente gosto de usar BDUnit para testes funcionais assim, mas há quem não gosta. Para não dizer que temos apenas uma solução resolvi escrever esse post.
Lets go..
Starting..
É comum achar que não é possível chamar o método real usando mock, mas analisando a documentação vamos encontrar um cara que permite chamar o método real, usando o mesmo contexto de mock,. Isso permite manter todo seu test com mock e ainda cobrir o que é de fato necessário.
No padrão de uso da mock, o código a seguir não rola cobertura, uma vez que estamos usando a mock, então o método real não é chamado:
@Test
public void testBuscaEmailCadastrado() {
user.setEmail(“camilo@”);
when(usuarioDaoMock.buscaUsuarioPorEmail(user)).thenReturn(user);
assertNotNull(usuarioDaoMock.buscaUsuarioPorEmail(user));
}
Como podemos ver na imagem acima, vermelho significa que não tem cobertura naquele código, uma vez que não há test case chamando ele direto.
E como resolver isso?
Para resolver é muito simples. Porém, antes de apresentar a solução vamos a outro fato tradicional, testar métodos do tipo void. Sabemos que com assert não é possível testar um método void, uma vez que este retorna “nada”. Mas com mock podemos chamar um método void e testá-lo, afetando assim a cobertura. Vejamos como:
O método doCallRealMethod() permite chamar o método real da mock, independente do tipo deste método. Sendo assim, void agora pode ser chamado e verificado no seu test case. É comum ver programadores tendo que converter um determinado método do tipo void para return alguma coisa só para satisfazer o test case. Sem o uso de mock (mockito) temos que fazer isso, porque não temos nenhum assert para verificar um tipo void que não retorna “nada”.
Observe na imagem a seguir o resultado, agora está cobrindo o DAO:
Note: segundo a documentação, o uso doCallRealMethod() é algo que deve ser feito cuidadosamente, pois significa que há algum tipo de complexidade no seu código, mas também não deixam de falar que há casos raros onde é possível usar the partial mock warning (é o nome que se dá quando chamamos um método real usando mock).
O code:
1 Mockito.doCallRealMethod().when(usuarioDaoMock).buscaUsuarioPorEmail(user);
2 assertEquals(usuarioDaoMock.buscaUsuarioPorEmail(user).getEmail(),user.getEmail());
A leitura do code: “chame o método real quando o método buscaUsuarioPorEmail for chamado pela usuariodaomock e passe o valor user para ele”.
Assim o mockito vai lá na classe que possui o método real e chama ele de fato, como vimos na imagem anterior, onde o código passa a ser coberto.
Um possível Problema
O único problema é que precisamos ter o banco de dados rodando, ou seja, UP para as funções que precisa consultar. Pode parecer óbvio, mas nem tanto, porque quando usamos a mock apenas, esta simula a chamada e o valor esperando independente do banco estar ON/OFF.
Resultado com o banco OFF é o seguinte:
org.hibernate.exception.JDBCConnectionException: Cannot open connection
Mas não esqueçam que ainda temos a vantagem de testar métodos do tipo void, fazendo a cobertura passar por ele. No contexto acima, na maioria das vezes vamos ter um BD ON, pois queremos ver se o nosso CRUD/DAO está fazendo o que de fato esperamos que ele faça, que é a comunicação com o BD, porém daí já estaríamos caminhando mais para tests funcionais que tests cases de fato.
Na imagem a seguir temos a cobertura em todo DAO. Observe que foi implementado um novo método que busca no banco um email e este não existe, daí verificamos se de fato o código entra no catch e este está coberto.
Cobertura antes
Cobertura depois
Mas, uma solução também é usar o banco em memoria como HSQLDB assim você poderá executar seus testes contra o banco automaticamente, ou seja, você não precisar iniciar ou parar o banco.
Vou ficando por aqui.
Abracos, see ya!!
Criando projeto JSF com Maven no Eclipse
Olá Pessoal,
No post de hoje vamos ver como criar um projeto JSF no Eclipse já suportando o Maven. Parece algo simples, concorda? Mas pode dar uma dor de cabeça, e veremos o motivo.
Lets GO…
Starting…
Antes de mais nada instale o Jboss tools, conforme este post. Após a instalação, vamos ver o cenário que temos.
- Maven 3.x
- Eclipse Helios
Cenário 1
Você pode adicionar o maven ao seu projeto manualmente, ou seja, basta adicionar o pom.xml ao projeto e fazer as devidas configurações. Ideal é quando você já tem um projeto e no inicio não usava o maven, mas resolveu adotar agora, daí você não vai querer deletar o projeto e criar um novo “maven Project” certo. Mas sabemos que fazer configuração manualmente sempre é chato. Porém essa é uma forma de você adicionar o Maven ao seu projeto.
Cenário 2
Você está querendo começar um projeto do zero, tipo JSF Project. Mas, ao criar, vê que ele não está na estrutura do maven. E o que fazer? Podemos ir pelo cenário 1. Mas e se eu quiser já criar automático? Há uma opção usando o File New Maven Project.
Quando escolhemos Maven Project há varias opções de criar um projeto, desde um simple maven Project, até um Project webapp. Na imagem a seguir você pode ver as opções de maven Project disponíveis, porém muitos deles estão com bugs críticos que não cria o projeto ou dá umas exceções e trava tudo. Um exemplo é a appfuse para jsf + hibernate + Spring. Se tivesse funcionando seria muito show, mas infelizmente não está. E o que fazer ir para o cenário 1?
É o que fiquei pensando. Apesar de podermos criar a nossa própria estrutura archetypes http://maven.apache.org/guides/mini/guide-creating-archetypes.html e ser fácil e rápido, mesmo assim ainda fiquei incomodado pelo fato de não conseguir gerar um projeto JSF, já com o Maven consegui com apenas alguns cliques.
Solução?
Sim, depois de muitas horas tentando entender o motivo e quebrando a cara com alguns plugins, achei um workaround. Vamos lá:
Crie um Maven Project (File è new è Project è maven project)
Na próxima tela deixe assim:
Clica em next e na tela seguinte vamos escolher maven-achetype-webapp
Clica em next
E agora vamos preencher. Estou presumindo que você já conhece o maven, então não irei explicar o que significa cada campo. Veja como ficou a minha:
Clique em finish.
Como você percebeu, o workaround foi criar um projeto do tipo webapp, mas ainda o projeto não tem suporte JSF, podemos fazer isso manualmente ou automaticamente. Clique com o botão direito no projeto e escolha configure >> add jsf capabilities:
Escolha o Servlet version 2.5
Clique em finish, no warning que aparecer clique em Yes
O projeto vai ficar “quebrado”, pois a versão do web.xml está diferente. Abra o web.xml e altere o version para 2.5
Agora precisamos adicionar as libs para JSF no pom.xml. Abra o pom.xml e clique na aba dependencies
E adicione:
com.sun.faces jsf-api
com.sun.faces jsf-impl
Não esqueça de adicionar também:
javax.servlet javax.servlet-api
javax.servlet jstl
Feito isso seu projeto deve tá assim:
Workaround para Windows 7
Quem tem Windows 7 pode se deparar com o problema de não conseguir executar “cmd” e para resolver o problema basta adicionar ao path do sistema o seguinte valor:
%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem
O Maven não está atualizando no eclipse
Passei por esse problema de alterar o pom.xml e o maven não fazer o download das libs e a modificação não refletir no eclipse, daí basta forçar o download:
mvn eclipse:eclipse -DdownloadSources=true
Vou ficando por aqui, espero que tenham gostado do post.
See ya!
Projeto JEE com jetty + maven
Olá Pessoal,
O post de hoje saiu após muito sofrimento de tentar criar um maven Project rodando com Jetty, mas que eu não precisasse ter o jetty na máquina local e que desse suporte JSF. Parece algo simples e fácil, concorda? Mas me deu uma dor de cabeça e consumiu praticamente 2 dias de tentativas. Vamos entender o motivo.
Lets go …
Contexto
Bem, eu precisava criar um projeto para ter tudo gerenciado pelo maven. Primeiro eu decidi sair do TomCat e ir para o Jetty, pois a performance do tomcat e outros problemas que estava tendo com o servidor estavam sendo criticos, mas eu não queria ter o jetty na máquina local para poder rodar minha app, queria fazer isso de maneira simples pelo maven, daí veio as alternativas:
- Criar um projeto webapps usando o archetype do maven;
- Criar um dynamic web Project e adicionar o maven ;
- Criar um projeto maven usando archetype JSF disponíveis;
- Criar um projeto JSF e depois adicionar maven + jetty
- Plugin jetty Eclipse via Eclipse Market
Nenhuma dessas alternativas funcionou como eu queria. Muitos dos archetype disponíveis lá no maven estão “bugados” e simplesmente não iniciam aplicação. A opção 2 só funcionava sem JSF, ao adicionar “JSF capacibilities” pelo eclipse simplesmente exigia ter o jetty local para apontar. O mesmo para a opção 4. A opção 3 simplesmente nenhum dos archtype que tentei subia app. Tentei até arrumar, mas era muita mão e tempo que seria gasto. A opção 5 ainda está a desejar, os plugins que testei disponíveis no eclipse market simplesmente estavam cheio de bugs, fora quando não travava a IDE.
E a solução?
Mais simples do que imaginei. Apenas criei um simple maven Project.
Clique em finish. E terá um projeto com a estrutura a seguir:
Vamos criar nosso web.xml, WEB-INF e lib.
Para os arquivos web.xml e face-config.xml, é simples. Apenas crie um JSF Project e copie o web.xml e face-config.xml gerado. Não recomendo querer criar os arquivos na mão, pois você pode ter erros por digitar algo errado e acabar perdendo tempo fixar algo que não agrega muito valor.
Adicione as libs que você precisa:
Novamente copiei do projeto jsf. E adicionei as do JSF 2.0 : jsf-api-2.0.9.jar e jsf-impl.jar
Agora vamos configurar o arquivo pom do maven:
Feito isso crie um arquivo index.jsp em webapp e dentro de body coloque o que achar necessário para testar.
Observe que criei um arquivo xhtml para poder testar o JSF 2.0. Nele apenas uso uma tag <h:outputLabel value=”Lopes Neto” /> assim verifico se realmente o projeto está dando suporte ao JSF.
Rodando aplicação
Para rodar aplicação é bem simples, clique com o botão direito no projeto e siga os passos a seguir:
Clique em maven build e vamos adicionar um build para iniciar o maven
<img mavenrunconfigjettyrun>
Apenas selecione o projeto em base directory e em goals coloque jetty:run que é para iniciar o servidor.
E agora basta acessar e ver sua aplicação rodando sem o jetty local, apenas através do maven:
Enfim, foi a forma que consegui fazer o maven rodar para projetos JEE com JSF sem ter o jetty local na máquina. Não posso dizer que fiquei satisfeito com essa solução, mas foi a que me deu menos dor de cabeça.
Vou ficando por aqui. See ya!!
Abraços!
DBUnit com HSQLDB + Hibernate + maven
Olá pessoal!
No post de hoje vamos ver como executar nossos unit tests usando o DBunit com HSQLDB em memória, tendo o Hibernate como framework de persistencia e usando o maven. por que isso tudo? Eu passei por uns problemas chatos de configuração que normalmente não temos quando fazemos testes de cada um desses recursos separados, mas, quando tive que colocar tudo na mesma panela, surgiram uns problemas mais chatos para nós, desenvolvedores, estou falando daquelas exceções de não achar o arquivo, exceções genéricas dos frameworks, que nos faz ficar horas e horas googlando, etc.
lets go..
O que vou considerar?
Que você já conhece Hibernate e conhece o DBunit, porém agora pretende rodar seus testes em um projeto do tipo maven e que você tem dois arquivos hibernate.cfg.xml, um para os testes e outro para a aplicação em si.
O problema
Tudo começou quando, ao executar meus testes, simplesmente recebi aquela velha mensagem: cannot open JDBC Connection. Eu disse “como assim? O hibernate.cfg.xml está lá”. Daí comecei a investigar. Um ponto eu já sabia e publiquei aqui nesse troubleshooting: o maven procura o hibernate.cfg.xml em src/main/resources. E para os testes? Ele procura em src/test/resources. Até parece lógico, mas errei aqui e não coloquei meu arquivo de hibernate.cfg.xml de teste nesse local. Porém, veio outro problema: eu tinha renomeado meu arquivo hibernate.cfg.xml para hibernateTest.cfg.xml. Por que? Simplesmente queria ter essa diferença. E deixava assim a configuração nos meus testes:
protected IDatabaseConnection getConnection() throws Exception {
conn = new DatabaseConnection(new Configuration().configure(“hibernateTest.cfg.xml”)
.buildSettings().getConnectionProvider().getConnection());
return conn;
}
Simplesmente recebia:
Dai o que fiz?
Mudei o arquivo para hibernate.cfg.xml e rodei a aplicação e o resultado:
Isso me custou umas 3hrs do meu dia. Infelizmente não fui pesquisar porque com o nome diferente do hibernate o maven não encontrava o arquivo, somente com o nome default.
O arquivo do DBunitTest é o mesmo que vimos nos outros post da série, a única diferença é que temos um projeto do tipo “simple maven project”.
Hibernate.cfg.xml para o HSQLDB
<session-factory>
<property name=”hibernate.connection.driver_class”>org.hsqldb.jdbcDriver</property>
<property name=”hibernate.connection.url”>jdbc:hsqldb:mem:db</property>
<property name=”hibernate.connection.username”>sa</property>
<property name=”hibernate.dialect”>org.hibernate.dialect.HSQLDialect</property>
<property name=”hibernate.show_sql”>true</property>
<property name=”hibernate.hbm2ddl.auto”>create-drop</property>
<mapping class=”com.camilolopes.qa.model.dao.bean.Account”/>
</session-factory>
Configuração do pom.xml Adicione as dependencias abaixo:
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.10.Final</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.4.8</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
Crie um bean e um teste para persistir o objeto:
Bean
@Entity
@Table(name=”account”)
public class Account {
@Id
@GeneratedValue
@Column(name=”ID”)
private Long id;
@Column(length=20,name=”TYPE”)
private String type;
}
Test
A classe de test deverá estar assim, e omitir o que não mudou do outro arquivo, como a conexão e o load do .xml.
public DBUnitTest() {
try {
session = getSessionFactory().openSession();
getDataSet();
} catch (Exception e) {
e.getMessage();
}
}
public static SessionFactory getSessionFactory() {
sessionFactory = new Configuration().configure().buildSessionFactory();
return sessionFactory;
}
@Test
public void testSave(){
session.beginTransaction();
Account account = new Account();
account.setType(“USER”);
session.save(account);
}
Enfim, é isso ai. Caso precise rodar seus unit tests com maven + hibernate + hsqldb, sem ter dor de cabeça com arquivo de configuração, essa foi a solução que encontrei.
Abracos, see ya!!