JUnit/Easymock - Como efetuar testes em Beans

Estou com a seguinte situação, nescessito criar um teste unitário para um bean (Código 1), porém para que o teste desse certo precisaria utilizar um mock para “simular” uma conexão no banco, creio eu que é a maneira correta e/ou mais facíl. Porém estou com dificuldades de utilizar o Easymock para criar o mock (Código 2) que simularia a conexao ao banco… Até o momento já li alguns tutoriais que encontrei no google, inclusive os da Improve It, mas não achei nada que desse uma dica de como chegar ao resultado esperado.

Código 1

[code]public class NotaFiscalServiceBean extends AbstractCrudServiceBean implements NotaFiscalService { // NOPMD by gkauer on 03/02/10 15:14

private static final transient Logger LOGGER = Logger.getLogger(NotaFiscalServiceBean.class);

private static final String MAIL_SEPARATOR = ";";

private transient DocumentoService documentoService;

private transient TipoDocumentoService tipoDocumentoService;

private transient NotaFiscalXmlParserService notaFiscalXmlParserService;

private transient ConhecimentoTransporteXmlService conhecimentoTransporteXmlService;

private transient PedidoService pedidoService;

private transient HistoricoNotaFiscalService historicoNotaFiscalService;

private transient NotaFiscalXmlService notaFiscalXmlService;

private transient ItemPedidoService itemPedidoService;

/**
 * Consulta nativa, faz join com tabela nao mapeada nos relacionamentos do
 * Hibernate. Utilizar na tela de pesquisa.
 * 
 * @param paginationCriteria
 *            paginationCriteria
 * @param findCriteria
 *            findCriteria
 * @return PaginatedList
 */
public PaginatedList<Map<String, Object>> findNative(final PaginationCriteria paginationCriteria, final FindCriteria findCriteria) { // NOPMD by gkauer on 03/02/10 15:14
	final ValueObjectCriteria<NotaFiscal> voc = (ValueObjectCriteria<NotaFiscal>) findCriteria;

	final Map<String, Object> parameters = new HashMap<String, Object>();
	final StringBuilder query = new StringBuilder();

	query.append(" select distinct ");
	query.append(" nf.codigo_nota_fiscal as id,");
	query.append(" nf.numero_nota_fiscal as numeroNotaFiscal,");
	query.append(" nf.tipo_origem as tipoOrigem,");
	query.append(" nf.valor_total_bruto as valorTotalLiquido,");
	query.append(" nf.data_hora_entrega as dataHoraEntrega,");
	query.append(" nf.data_hora_emissao as dataHoraEmissao,");
	query.append(" cli.razao_social as razaoSocialCliente,");
	query.append(" forn.razao_social as razaoSocialFornecedor,");
	query.append(" a.data_hora_agendamento as dataHoraAgendamento,");
	query.append(" cli.codigo_localizacao as codigoCliente,");
	query.append(" le.codigo_local_entrega as localEntrega");

	query.append(" from nota_fiscal nf ");
	query.append(" inner join pedido_nota_fiscal pnf on pnf.codigo_nota_fiscal = nf.codigo_nota_fiscal");
	query.append(" inner join pedido p on p.codigo_pedido = pnf.codigo_pedido");
	query.append(" inner join nota_fiscal_agendamento nfa on nfa.codigo_nota_fiscal = nf.codigo_nota_fiscal");
	query.append(" join agendamento a on a.codigo_agendamento = nfa.codigo_agendamento");
	query.append(" join local_entrega le on le.codigo_local_entrega = a.codigo_local_entrega");
	query.append(" join localizacao forn on forn.codigo_localizacao = nf.codigo_fornecedor");
	query.append(" join localizacao cli on cli.codigo_localizacao = nf.codigo_comprador");
	query.append(" left join pedido pt on pt.codigo_pedido = a.codigo_pedido_transferencia");

	if (isNotBlank((String) voc.getParameter("numeroPedidoInicial"))) {
		query.append(" and p.numero_pedido >= :numeroPedidoInicial \n");
		parameters.put("numeroPedidoInicial", Integer.decode((String) voc.getParameter("numeroPedidoInicial")));
	}

	if (isNotBlank((String) voc.getParameter("numeroPedidoFinal"))) {
		query.append(" and p.numero_pedido <= :numeroPedidoFinal \n");
		parameters.put("numeroPedidoFinal", Integer.decode((String) voc.getParameter("numeroPedidoFinal")));
	}

	if (isNotBlank((String) voc.getParameter("numeroNotaFiscalInicial"))) {
		query.append(" and nf.numero_nota_fiscal >= :numeroNotaFiscalInicial \n");
		parameters.put("numeroNotaFiscalInicial", Integer.decode((String) voc.getParameter("numeroNotaFiscalInicial")));
	}

	if (isNotBlank((String) voc.getParameter("numeroNotaFiscalFinal"))) {
		query.append(" and nf.numero_nota_fiscal <= :numeroNotaFiscalFinal \n");
		parameters.put("numeroNotaFiscalFinal", Integer.decode((String) voc.getParameter("numeroNotaFiscalFinal")));
	}

	final Double valorInicial = (Double) findCriteria.getParameter("valorInicial");
	if (valorInicial != null) {
		query.append(" and nf.valor_total >= :valorInicial \n");
		parameters.put("valorInicial", valorInicial);
	}

	final Double valorFinal = (Double) findCriteria.getParameter("valorFinal");
	if (valorFinal != null) {
		query.append(" and nf.valor_total <= :valorFinal \n");
		parameters.put("valorFinal", valorFinal);
	}

	final Date dataEmissaoInicial = (Date) findCriteria.getParameter("dataEmissaoInicial");
	final Date dataEmissaoFinal = (Date) findCriteria.getParameter("dataEmissaoFinal");
	if (dataEmissaoInicial != null && dataEmissaoFinal != null) {
		query.append(" and (nf.data_hora_emissao between :dataEmissaoInicial and :dataEmissaoFinal) \n");
		parameters.put("dataEmissaoInicial", dataEmissaoInicial);
		parameters.put("dataEmissaoFinal", dataEmissaoFinal);
	}

	final Date dataEntregaInicial = (Date) findCriteria.getParameter("dataEntregaInicial");
	final Date dataEntregaFinal = (Date) findCriteria.getParameter("dataEntregaFinal");
	if (dataEntregaInicial != null && dataEntregaFinal != null) {
		query.append(" and (nf.data_hora_entrega between :dataEntregaInicial and :dataEntregaFinal) \n");
		parameters.put("dataEntregaInicial", dataEntregaInicial);
		parameters.put("dataEntregaFinal", dataEntregaFinal);
	}

	if (isNotBlank((String) findCriteria.getParameter("tipoOrigem"))) {
		query.append(" and nf.tipo_origem = :tipoOrigem \n");
		parameters.put("tipoOrigem", voc.getParameter("tipoOrigem"));
	}

	if (isNotBlank((String) findCriteria.getParameter("tipoPedido"))) {
		query.append(" and p.tipo_pedido = :tipoPedido \n");
		parameters.put("tipoPedido", voc.getParameter("tipoPedido"));
	}

	if (isNotBlank((String) voc.getParameter("numeroPedidoTransferenciaInicial"))) {
		query.append(" and pt.numero_pedido >= :numeroPedidoTransferenciaInicial \n");
		parameters.put("numeroPedidoTransferenciaInicial", voc.getParameter("numeroPedidoTransferenciaInicial"));
	}

	if (isNotBlank((String) voc.getParameter("numeroPedidoTransferenciaFinal"))) {
		query.append(" and pt.numero_pedido <= :numeroPedidoTransferenciaFinal \n");
		parameters.put("numeroPedidoTransferenciaFinal", voc.getParameter("numeroPedidoTransferenciaFinal"));
	}

	if (findCriteria.getParameter("idFornecedor") != null) {
		query.append(" and nf.codigo_fornecedor = :idFornecedor \n");
		parameters.put("idFornecedor", voc.getParameter("idFornecedor"));
	}

	if (isNotBlank((String) findCriteria.getParameter("idFilial"))) {
		query.append(" and nf.codigo_comprador = :idFilial \n");
		parameters.put("idFilial", Integer.decode((String) voc.getParameter("idFilial")));
	}

	query.append(" order by nf.numero_nota_fiscal desc ");

	final List<Object[]> retorno = findByNativeQuery(query.toString(), parameters);

	final List<Map<String, Object>> resultPesquisa = new ArrayList<Map<String, Object>>();
	for (Object[] obj : retorno) {
		int index = 0;
		final Map<String, Object> map = new HashMap<String, Object>();
		map.put("id", obj[index++]);
		map.put("numeroNotaFiscal", obj[index++]);
		map.put("tipoOrigem", obj[index++]);
		map.put("valorTotalLiquido", Double.valueOf(((BigDecimal) obj[index++]).doubleValue()));
		map.put("dataHoraEntrega", obj[index++]);
		map.put("dataHoraEmissao", obj[index++]);
		map.put("razaoSocialCliente", obj[index++]);
		map.put("razaoSocialFornecedor", obj[index++]);
		map.put("dataHoraAgendamento", obj[index++]);
		map.put("codigoCliente", obj[index++]);
		map.put("localEntrega", obj[index++]);

		resultPesquisa.add(map);
	}

	return new PaginatedList<Map<String, Object>>(resultPesquisa, resultPesquisa.size(), paginationCriteria);
}

}[/code]

Código 2

[code]import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

import com.neogrid.bfw.util.FindCriteria;
import com.neogrid.bfw.util.PaginatedList;
import com.neogrid.bfw.util.PaginationCriteria;
import com.neogrid.bfw.util.ValueObjectCriteria;
import com.neogrid.elog.domain.NotaFiscal;
import com.neogrid.elog.service.impl.NotaFiscalServiceBean;

public class TestNotaFiscalServiceBean {

private transient NotaFiscalServiceBean bean;
private transient PaginationCriteria paginationCriteria;
private transient PaginationCriteria paginationCriteriaNulo;
private transient FindCriteria findCriteriaNulo;
private transient PaginatedList<Map<String, Object>> listaRetorno;
private transient final ValueObjectCriteria<NotaFiscal> voc = new ValueObjectCriteria<NotaFiscal>();


@Before
public void setUp() throws Exception {
	
	bean = new NotaFiscalServiceBean();
	
	paginationCriteriaNulo = null;
	findCriteriaNulo = null;
	paginationCriteria = new PaginationCriteria();
	
	Date dataInicial = new Date("01/01/2010");
	Date dataFinal = new Date("02/28/2010");
	Date dataEntregaInicial = null;
	Date dataEntregaFinal = null;
	List lista = new ArrayList();
	String idFornecedor = null;
	
	voc.addParameter("valorInicial", null);
	voc.addParameter("valorFinal", null);
	voc.addParameter("dataEmissaoInicial", dataInicial);
	voc.addParameter("dataEmissaoFinal", dataFinal);
	voc.addParameter("dataEntregaInicial", dataEntregaInicial);
	voc.addParameter("dataEntregaFinal", dataEntregaFinal);
	voc.addParameter("idFornecedor", idFornecedor);
	
	listaRetorno = new PaginatedList(lista, 1000, paginationCriteria);
}

/*
 * Verifica se quando chamar o método findNative passando null
 * apenas no primeiro parâmetro vai apontar erro de NullPointerException
 * 
 * Resultado Esperado: NullPointerException
 */
@Test
public final void testFindNative() {
	listaRetorno = bean.findNative(paginationCriteria, voc);
}

}

[/code]

Se alguém tiver alguma dica ou algum exemplo mais complexo e mais próximo da realidade que apresento agradeço.

cara teu primeiro passo é criar um mock do metodo

findByNativeQuery(query.toString(), parameters);  

para ele retornar o resultado esperado.

Posso saber o por que de testar essa informação?

Você não deve testar consultas no banco a não ser que essa consulta nunca mude, não é vantagem ficar tando manutenção em um teste que quebra a cada compilação.

Primeiro, onde acho algum manual de como criar mocks de métodos?

Ai que vem o problema, eu entrei recentemente em uma empresa que não tinha o costume de promover testes unitários.
Me deram a missão de iniciar a implementação deles e me veio a pergunta, “Por onde começar a implementar testes?”

Como o sistema esta “estável” pensei em começar pelas consultas chave. Aqueles pontos que não podem haver rupturas em momento algum…

Mas se tiver alguma ideia melhor estou aberto a sugestões.

Questão que vc deve pensar é essa:

Esse sistema foi feito para ser testado?

Para se usar testes unitarios deve-se usar a metodologia TDD baseada no teste, é muito dificil pegar um sistema que não foi projeto para isso e implementar os testes.

Eu gosto de usar o Mockito para os testes, é bem simples e facil de ser usado.

Por exemplo Para testar essa consulta chave que não pode falhar. Qual seria o criterio esperado para ela não falhar? o Tamanho maior que 0? Não ser gerada exception?
Mesmo assim são testes simples, e não avaliam corretamente o metodo.

Partindo do principio do TDD, para um determinada entrada teremos uma única saída.
É assim que deve funcionar, o que foi variavel se torna complicado de testar, por exemplo entrando a String “Joao”, deve retornar os joãos cadastrados. mas quantos joãos podem ter? o Ideal era simular a base com alguns joaos la dentro e ver se o retorno é o mesmo.

vou falar do mock com o Mockito, para adapta-lo para o Easymock não deve ser complicado

import static org.mockito.Mockito.*;

Qualquer qualquer = mock(Qualquer.class);
when(qualquer.getNome()).thenReturn("Teste");//o Metodo getNome ira retornar sempre "Teste"
ClasseTeste teste = new ClasseTeste (qualquer);

Se tiver alguma duvida posta ai que a gente ajuda.