Versão ALPHA! Este artigo está em versão 'Alpha' e, portanto, não foi ainda revisado corretamente

Implementando Consultas: Testes

Introdução

A partir do momento em que temos informações armazenadas (seja em uma agenda, CD ou Banco de Dados), podemos consultá-las. Essas consultas podem ser feitas manualmente (buscando em uma agenda) ou por um sistema/programa que traz as informações para a tela de seu computador.

Nota: A interface gráfica das consultas não fazem parte do escopo deste artigo, apenas os testes.

Antes de iniciar

Este item exige conhecimentos sobre:

Especificação

Siga o checklist abaixo: <table class="table table-bordered">

Quais campos devemos exibir? Serão necessários filtros? Se sim, quais? É preciso realizar consultas mais específicas?

</table>

Quais campos devemos exibir?

Imagine o seguinte cenário: Suponhamos que uma biblioteca de uma universidade já possui um banco de dados chamado BIBLIOTECA com centenas de livros armazenados. Porém, a biblioteca precisa que seus alunos e professores consigam consultar estes livros através dos computadores para obter sua localização nas prateleiras desta biblioteca. Considere que a classe-entidade Livro já existe.

public interface Livro {

  int getId();

  String getTitulo();
  
  String getTituloOriginal();

  int getLocalizacao();

  String getAutorPrincipal();
  
  String getAutorSecundario();
  
  LocalDate getPublicacao();
  
  String getDescricaoFisica();

}

Neste exemplo, temos um campo Título Original que, porventura, não será necessário exibir se estivermos consultando apenas livros no idioma português.
Em contrapartida, há pessoas que querem saber o Título Original do livro para comprá-lo em outro idioma.

Na dúvida, sempre pergunte ao seu líder de projeto! O que deve ser exibido dependerá de caso a caso!

Para este caso de uso, listaremos apenas alguns campos:

TITULO: É fundamental saber o título do livro;
LOCALIZACAO: O corredor e a prateleira;
AUTOR_PRINCIPAL: Muitos usuários consultam livros através de autores;
PUBLICACAO: Sabendo a data em que foi publicado, podemos escolher um outro livro mais recente;

Note que nosso cliente apenas deseja que alunos e professores consulte os livros no intuito de localizá-los nas prateleiras. Mas, isto não nos impede de pensar em futuras melhorias como é o caso da utilização do Título Original descrito acima.

Serão necessários filtros? Se sim, quais?

O filtro é necessário quando precisamos exibir uma consulta filtrada por um determinado atributo, ou seja, se criarmos um filtro por localização, obteremos como resposta todos os livros daquela determinada localização, por exemplo, livros do corredor 1 e prateleira 3. Este filtro é muito importante para este caso, já um filtro por publicação não resolveria este problema.

Contudo, você deve sempre focar em resolver o problema do seu cliente criando consultas e/ou filtros que de fato, resolvam estes problemas.

Você irá encontrar alguns casos que não necessitam de filtros, somente a consulta por ordenação atenderá os requisitos.

Veja este filtro por localização no item Implementação.

É preciso realizar consultas mais específicas?

Com o mesmo exemplo do livro, imagine a seguinte situação: Por alguma razão (que não é o foco neste momento) precisamos listar todos os livros que foram emprestados a um determinado aluno. Para isto, precisamos “buscar” este aluno na tabela ALUNO (supondo que já exista) e a partir deste, consultar os livros emprestados à ele.

Este tipo de situação tornou-se uma consulta específica, diferente de uma consulta onde queremos apenas os livros, ou seja, duas entidades relacionadas farão parte da consulta.

Você irá encontrar diversos casos destes dois tipos: “Listar funcionários de uma empresa X”, “listar somente os livros” , “listar os subordinados do gerente X da empresa Y”, entre outros.

Geralmente utilizamos algum atributo da entidade relacionada passando-a no argumento, ou os buscadores que podem retornar um objeto.

Para mais informações sobre Buscadores, leia aqui.

Implementação

Considerando que temos:

  1. A Classe-Entidade. Veja como criá-la aqui
  2. Todos os dados armazenados na tabela LIVRO. Veja como criá-la aqui
  3. O mini-arquivo.xml com estes dados. Veja como criá-lo aqui

Nota: Validaremos mais adiante se os dados no mini-arquivo são suficientes para os testes!

Siga o checklist abaixo: <table class="table table-bordered">

Preparar o teste e suas dependências Preparar o método de consulta com ordenação Preparar o método de consulta com filtro
<tr>    <td class="tac col2em">
<a id="topo_0_6"><input type="checkbox" /></a>

</td>

Consultas específicas

</tr> </table>

Preparar o teste e suas dependências

Crie a classe TesteDeConsultaDeLivro no pacote seu-projeto.ui.api do diretório src/test/java/.
Exemplo: br.com.objectos.dojo.biblioteca.ui.api.

public class TesteDeConsultaDeLivro {
}

Defina a classe como sendo de Teste e adicione o Módulo de Teste (através das anotações).

@Test
@Guice(modules = ModuloDeTesteObjectosDojo.class)
public class TesteDeConsultaDeLivro {
}

Importante: Cada projeto utiliza diferentes módulos de teste, atente-se a isto!

Declare uma variável de referência para ConsultaDeLivro. Esta realizará nossas consultas.

@Test
@Guice(modules = ModuloDeTesteObjectosDojo.class)
public class TesteDeConsultaDeLivro {

  @Inject
  private ConsultaDeLivro consulta;
  
}

Utilize o Ctrl + 1 nesta linha para que o Eclipse crie a classe no diretório /src/main/java/. Ela terá a seguinte estrutura:

public class ConsultaDeLivro {
 	}

Por fim, declare uma variável de referência para DBUnit que carrega o DefaultDataSet contendo o arquivo .xml (registros da tabela).

@Inject
private DBUnit dbUnit;
  
@BeforeClass
public void prepararDBUnit() {
  dbUnit.loadDefaultDataSet();
}

Crie um template no Eclipse para agilizar o procedimento.

Preparar o método de consulta com ordenação

Com as dependências adicionadas na classe (DBUnit, TestNG), seguimos para o passo “verificar os dados no arquivo.xml”.

Precisamos ter certeza que os dados mantidos no arquivo .xml são suficientes para realizar os testes, isto é, se os dados não são nulos para campos definidos NotNull, se os dados realmente existem, entre outros.

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
		 
	<BIBLIOTECA.LIVRO ID="2"
	TITULO="Scjp Sun Certified Programmer For Java 6"
	LOCALIZACAO="133" 
	AUTOR_PRINCIPAL="Bates, Bert" 
	PUBLICACAO="2008-01-01" />
	
	<BIBLIOTECA.LIVRO ID="1"
	TITULO="Java - Como Programar"
	LOCALIZACAO="123" 
	AUTOR_PRINCIPAL="Deitel" 
	PUBLICACAO="2010-01-01" />
	
</dataset>

LOCALIZACAO="133": A localização é dada por corredor (1) seguido de prateleira(33). E todos os campos são NotNull.

Crie o método de consulta com ordenação padrão por título (definido na especificação):

public void ordenacao_padrao_por_titulo() {
  FakeRequestWrapper wrapper = new FakeRequestWrapper();
  List<ConsultaDeLivroDTO> res = consulta.list(wrapper);
}

Mais uma vez Ctrl + 1 em consulta.list(wrapper); crie a classe no diretório /src/main/java/.

public class ConsultaDeLivro {    
  public List<ConsultaDeLivroDTO> list(RequestWrapper wrapper) {
    return null;
  }
}  

E a interface no mesmo diretório.

public interface ConsultaDeLivroDTO {
}	

Crie classes privadas que implemente a interface Function<F,T>:

private class ToTitulo implements Function<ConsultaDeLivroDTO, String> {
  @Override
  public String apply(ConsultaDeLivroDTO input) {
    return input.getTitulo();
  }
}

private class ToLocalizacao implements Function<ConsultaDeLivroDTO, Integer> {
  @Override
  public Integer apply(ConsultaDeLivroDTO input) {
    return input.getLocalizacao();
  }
}

private class ToAutorPrincipal implements Function<ConsultaDeLivroDTO, String> {
  @Override
  public String apply(ConsultaDeLivroDTO input) {
    return input.getAutorPrincipal();
  }
}

private class ToPublicacao implements Function<ConsultaDeLivroDTO, LocalDate> {
  @Override
  public LocalDate apply(ConsultaDeLivroDTO input) {
    return input.getPublicacao();
  }
}

Em todos as linhas de retorno utilize Ctrl + 1 para criar os métodos automaticamente na interface. Observação: Os tipos de retornos na interface devem ser primitivos.

A interface deve estar com esta estrutura.

public interface ConsultaDeLivroDTO {

  String getTitulo();

  int getLocalizacao();

  String getAutorPrincipal();

  LocalDate getPublicacao();

}	

Volte ao método de ordenação e comece a criar os Asserts para o teste.

public void ordenacao_padrao_por_titulo() {
  FakeRequestWrapper wrapper = new FakeRequestWrapper();

  List<ConsultaDeLivroDTO> res = consulta.list(wrapper);
  assertThat(res.size(), equalTo(2));
  
  List<String> titulos = transform(res, new ToTitulo());
  assertThat(titulos.get(0), equalTo("Java - Como Programar"));
  assertThat(titulos.get(1), equalTo("Scjp Sun Certified Programmer For Java 6"));
  
  List<Integer> localizacoes = transform(res, new ToLocalizacao());
  assertThat(localizacoes.get(0), equalTo(123));
  assertThat(localizacoes.get(1), equalTo(133));
  
  List<String> autores = transform(res, new ToAutorPrincipal());
  assertThat(autores.get(0), equalTo("Deitel"));
  assertThat(autores.get(1), equalTo("Bates, Bert"));
  
  List<LocalDate> publicacoes = transform(res, new ToPublicacao());
  assertThat(publicacoes.get(0), equalTo(new LocalDate(2010, 1, 1)));
  assertThat(publicacoes.get(1), equalTo(new LocalDate(2008, 1, 1)));
}

Importante: O método transform do com.google.common.collect.Lists em conjunto da interface Function<F,T> do com.google.common.base “divide” a tabela em colunas, assim, podemos consultar cada campo de uma única coluna.

Sempre utilize Ctrl + 2 seguido da letra L para criar as variáveis locais automaticamente. Você pode fazer isto em consulta.list(wrapper) e transform.

Agora o método de ordenação padrão está pronto.

Preparar o método de consulta com filtro

Utilizando o exemplo dado na especificação, iremos criar um filtro por localização dos livros.

public void filtro_por_localizacao() {
  FakeRequestWrapper wrapper = new FakeRequestWrapper();
  wrapper.put("localizacao", 123);

  List<ConsultaDeLivroDTO> res = consulta.list(wrapper);
  assertThat(res.size(), equalTo(1));
  assertThat(res.get(0).getLocalizacao(), equalTo(123));
}

Utilize os mesmos atalhos anteriores: Ctrl + 1 e Ctrl + 2 seguido da letra L.

A classe de teste está finalizada. Porém, se você executar o teste ele irá falhar porque não criamos a consulta ainda.

Consultas específicas

Se fosse necessário um consulta específica como “livros de um aluno” descrito anteriormente na especificação, precisariamos verificar se as tabelas ALUNO e LIVRO possuem atributos semelhantes como id, matricula, etc. Utilizaremos o LIVRO_ID contido na tabela ALUNO (os ids são muito úteis para o relacionamento de entidades).

  public void ordenacao_padrao() {
    FakeRequestWrapper wrapper = new FakeRequestWrapper();
    int id = 1;
    
    List<ConsultaDeLivroDTO> res = consulta.list(id);
  } 

Haverá situações (serviços) onde você perceberá que passar um objeto no argumento será mais viável do que um atributo. Tudo dependerá dos requisitos. Desta forma, o método ficaria assim:

  public void ordenacao_padrao() {
    FakeRequestWrapper wrapper = new FakeRequestWrapper();
    Aluno aluno = buscarAluno.porId(1);
    
    List<ConsultaDeLivroDTO> res = consulta.list(aluno);
  } 

Veja os seguintes Asserts deste teste específico:

  assertThat(res.size(), equalTo(1));
  
  List<String> titulos = transform(res, new ToTitulo());
  assertThat(titulos.get(0), equalTo("Java - Como Programar"));
	  
  List<Integer> localizacoes = transform(res, new ToLocalizacao());
  assertThat(localizacoes.get(0), equalTo(123));
	  
  List<String> autores = transform(res, new ToAutorPrincipal());
  assertThat(autores.get(0), equalTo("Deitel"));
  
  List<LocalDate> publicacoes = transform(res, new ToPublicacao());
  assertThat(publicacoes.get(0), equalTo(new LocalDate(2010, 1, 1)));

Isto não impede de buscar um aluno através de outros atributos como id, turma, curso e etc.

Para mais informações acesse os códigos nos links abaixo:

TesteDeConsultaDeLivro.java
mini-biblioteca.xml

Siga para o próximo passo. As consultas! Continuar!
Leia mais uma vez! Revisar!


 
 

objectos, Fábrica de Software LTDA

  • R. Demóstenes, 627. cj 123
  • 04614-013 - Campo Belo
  • São Paulo - SP - Brasil
  • +55 11 5093-8640
  • +55 11 2359-8699
  • contato@objectos.com.br