Estamos fazendo uma aplicação utilizando o JSF e o GlassFish v2.
Existe um pequeno problema: não sei como fazer para efetuar o teste unitário de um Session Bean (anotado como @Stateless) têm uma propriedade EntityManager que é injetada através da anotação @PersistenceContext.
Se eu testo com o JUnit, ele dá NullPointerException, e com razão, pois o container EJB é que injeta a referência ao EntityManager, como estou rodando fora do container está nulo. Vocês sabem de alguma maneira de efetuar o teste unitário In-Container?
Obviamente, existem vários frameworks que te ajudam nessa tarefa, como EasyMock e Mockito (recomendo o último). Assim, você teria algumas coisa mais elaborada, como:
EntityManager em = mock(EntityManager.class);
Query q = mock(Query.class);
when (em.createQuery("sua consulta aqui =P")).thenReturn(q);
when(q.list()).thenReturn(listaDeEntidadesPreConfiguradas);
SeuSessionBean bean = new SeuSessionBean(em); //Nota: você está realizando injeção de dependências pelo construtor, aqui. Lembre-se de ter dois construtores, um com e outro sem parâmetros, para que seu contêiner não se perca na hora de executar o código.
De maneira que você não precisa de toda a complexidade de um contêiner, só precisa que, uma vez que seu código execute essa consulta, você tenha o resultado que espera, tudo bem?
Eu acho que você não quer usar mock, só quer testar a DI pra ver se funciona. Se você está usando testes unitários, mostre-nos a sua classe de teste. Eu faria assim: sobe o servidor, cria o context no setUp (se for JUnit) que é override e os testes rodariam perfeitamente.
De qualquer forma, mock pode ser um pouco complicado e fora de questão por enquanto, ainda mais se você só quer ver se consegue ver se o EntityManager foi injetado corretamente.
Obviamente, existem vários frameworks que te ajudam nessa tarefa, como EasyMock e Mockito (recomendo o último). Assim, você teria algumas coisa mais elaborada, como:
EntityManager em = mock(EntityManager.class);
Query q = mock(Query.class);
when (em.createQuery("sua consulta aqui =P")).thenReturn(q);
when(q.list()).thenReturn(listaDeEntidadesPreConfiguradas);
SeuSessionBean bean = new SeuSessionBean(em); //Nota: você está realizando injeção de dependências pelo construtor, aqui. Lembre-se de ter dois construtores, um com e outro sem parâmetros, para que seu contêiner não se perca na hora de executar o código.
De maneira que você não precisa de toda a complexidade de um contêiner, só precisa que, uma vez que seu código execute essa consulta, você tenha o resultado que espera, tudo bem?
[]´s[/quote]
Caro asaudate, agradeço muito a elaborada resposta que me enviou, porém não compreendo como esse tipo de coisa vai efetivamente testar o meu bean de seção… :shock:
[quote=Andre Brito]Eu acho que você não quer usar mock, só quer testar a DI pra ver se funciona. Se você está usando testes unitários, mostre-nos a sua classe de teste. Eu faria assim: sobe o servidor, cria o context no setUp (se for JUnit) que é override e os testes rodariam perfeitamente.
De qualquer forma, mock pode ser um pouco complicado e fora de questão por enquanto, ainda mais se você só quer ver se consegue ver se o EntityManager foi injetado corretamente.[/quote]
Sobre o primeiro parágrafo eu fiz exatamente isso e não funcionou…
Sobre o segundo parágrafo eu não quero somente ver se o EntityManager foi injetado corretamente quero pegar os beans de seção dele um a um e testá-los…
[quote=Carlos_ds_jar]
Caro asaudate, agradeço muito a elaborada resposta que me enviou, porém não compreendo como esse tipo de coisa vai efetivamente testar o meu bean de seção… :shock: [/quote]
Você usa isso para testar somente a lógica. O caso, quando se usa mocks, é que você não quer testar o acesso ao banco, mas sim, a lógica de acesso ao banco. Injetar um mock no seu bean de sessão vai fazer com que você não tenha NullPointer num ponto onde você não precisa testar, pois é assumido que a lógica de acesso ao banco de dados funciona (além disso, um teste que envolva a integração com o banco de dados não é mais um teste unitário, mas sim, um teste de integração). Você usa mocks, portanto, em pontos onde a lógica somente naquele ponto em específico precisa ser testada - isso vale, inclusive, em casos onde um session bean é injetado em outro.
Para clarificar melhor, acho uma boa idéia dar uma olhada neste link.
[quote=Carlos_ds_jar]Mais uma vez muito obrigado pela resposta, mas como vc disse:
Eu não quero testar nem o banco nem a lógica que cerca o seu acesso, eu quero testar uma lógica qualquer que está no meu SessionBean![/quote]
Espera, acho que não estou me fazendo entender… deixa eu explicar um pouco melhor.
Vamos supor o seguinte SB:
@Stateless
public class ControladorFabrica {
@PersistenceContext
private EntityManager em;
public void desativarEmpregado (Empregado empregado) throws AplicacaoException{
//Certifica-se de que empregado pode ser desativado
if (empregado.getName() != null) { //1
empregado.setAtivo(false); //1
em.merge(empregado);
}
else {
throw new AplicacaoException ("O estado atual do empregado não é válido"); //1
}
}
}
No caso deste código, vamos supor que eu quero fazer um teste para que eu sempre, sempre saiba que a lógica de teste do estado do empregado está sendo executada. Assim, basta com que eu execute o método, só que… o que eu faço com aquele EntityManager alí??? Teoricamente, para testar isso, eu preciso de um EntityManager, certo??
É aí que entra o mock. Como a integração com banco de dados está fora do escopo (senão, seria um teste de integração), eu quero testar SOMENTE os trechos de código que eu marquei com //1. Neste caso, eu refatoro meu Session Bean de maneira que ele passe a aceitar um mock do EntityManager, fazendo com que a lógica seja testada e excluindo o uso do EntityManager. O SB refatorado ficaria assim:
@Stateless
public class ControladorFabrica {
@PersistenceContext
private EntityManager em;
public ControladorFabrica(EntityManager em) {
this.em = em;
}
public ControladorFabrica() {}
public void desativarEmpregado (Empregado empregado) throws AplicacaoException{
//Certifica-se de que empregado pode ser desativado
if (empregado.getName() != null) { //1
empregado.setAtivo(false); //1
em.merge(empregado);
}
else {
throw new AplicacaoException ("O estado atual do empregado não é válido"); //1
}
}
}
Ou seja, você deve refatorar o bean para que ele fique test-friendly (como, aliás, é citado no link que te passei).
Espero que agora fique mais claro. Qualquer coisa, só falar.