Como testar Session Beans no Glassfish?

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?

Obrigado pela atenção!

Você que testar a integração com o banco? Ou somente fazer o teste unitário?

Para unitário teste voê poderia criar um método de set para o EntityManager e passar um Mock dele.

Agora se você quiser testar sua integração com o banco acho que esse exemplo aqui pode ajudar:
http://openejb.apache.org/3.0/injection-of-entitymanager-example.html

Abrass.

Desculpe a ignorancia, mas o que é um Mock?

É uma entidade burra, sem lógica… do tipo, crie uma implementação da interface EntityManager que tenha um if:

if (request == "123testando") { return listaDeEntidadesPreConfiguradas; } else return null;

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

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.

É uma entidade burra, sem lógica… do tipo, crie uma implementação da interface EntityManager que tenha um if:

if (request == "123testando") { return listaDeEntidadesPreConfiguradas; } else return null;

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…

Qualquer sugestão é bem vinda!

[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.

[]´s

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=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.

[]´s