segunda-feira, 27 de fevereiro de 2012

Como configurar um projeto web com Maven + Eclipse

Algum tempo atrás estava procurando como configurar a dupla Eclipse + Maven para um projeto web e não consegui encontrar em um único site as instruções para realizar a tarefa, então estou escrevendo este guia para auxiliar os desenvolvedores com a mesma dificuldade.

Uso o Maven apenas para gerenciar as dependências, portanto a configuração realizada foi a mais simples possível para rodar o projeto.

O primeiro passo é instalar o m2e. Caso esteja usando o Eclipse Indigo basta ir no menu Help, depois Eclipse Market Place. Digite na caixa de busca m2e e instale o plugin.

O próximo passo é criar um Maven Project. Vá em File, New, Other e então procure por Maven Project.

Selecione a opção Create a simple project. Preencha o Group Id e Artifact Id do projeto, em Packing escolha a opção war, por se tratar de um projeto web.



Com o projeto criado, clique com o direito no projeto e escolha Properties >> Project Facets >> Convert to faceted from...

Marque a opção Dynamic Web Module.

Clique em Further Configuration avaliable e altere o Content Directory para: /src/main/webapp. Pressione OK.



Agora faremos com que as libs gerênciadas pelo maven sejam incluidas no deploy. Vá novamente nas propriedades selecione Deployment Assembly >> Add >> Java Build Path Entries >> Maven Dependencies.



Pronto! Agora é só adicionar suas dependências no pom.xml.

Abraços

segunda-feira, 6 de fevereiro de 2012

Query polimorfica com interfaces - Hibernate

Fazer uma query polimórfica em entidades relacionadas através de herança é muito simples. Porém as vezes desejamos executar uma query que busque todas as entidades que possuem determinado comportamento em comum, mas que não são da mesma hierarquia. Aqui é comum ver o desenvolvedor implementar herança de maneira errônea, apenas para conseguir esta funcionalidade.

Obs: Este tópico possui uma ótima discussão à respeito de herança e como ela pode ser prejudicial ao seu código.

Vamos supor que tenhamos o conceito de notificável em nosso sistema e queremos buscar por todas as entidades "notificáveis".

Como posso ter diversas entidades notificáveis que não fazem parte de uma hierarquia seria um erro usar herança. Então implementamos Notificavel como uma interface.


public interface Notificavel {

    public void notifica();

}



Suponhamos que temos duas entidades em que serão notificáveis: Sistema e Pessoa.


@Entity

public class Sistema implements Notificavel { ...



@Entity

public class Pessoa implements Notificavel { ...




Então realizamos a busca com a seguinte HQL:

String hql = "FROM br.com.renan.domain.Veiculo";


Note que colocamos o nome totalmente qualificado da interface, isso é necessário para que o hibernate saiba exatamente por qual interface buscamos.

Note que assim você consegue buscar por todas as entidades que implementem a inteface.

E por fim o teste:


@Test

public void deveRetornarDoisVeiculos() {

    List notificaveis = notificador.lista();

    assertEquals(2, notificaveis.size());

}


Aqui é possível encontrar o código completo do projeto.

Abraços.

sexta-feira, 18 de novembro de 2011

REST - Negociação de Conteúdo HTTP / Content Negotiation

Ultimamente tenho trabalhado em um projeto com arquitetura REST e um dos requisitos, é que consigamos integrar e atender de maneira flexível o maior número possível de clients, portanto fornecemos os recursos com diferentes tipos de formatos (media types).

Basicamente o client solicita o recurso e informa em qual formato deseja receber a representação, ou seja, ele negocia o conteúdo com o servidor. Para isso o client fará uma requisição GET e colocará no request header o atributo Accept com o valor desejado: application/xml, application/json e etc...

Nosso recurso irá fornecer a representação de um funcionário e além dos formatos como xml e json, neste post também faremos uma implementação que representa o funcionário através de uma imagem.

Caso o cliente consiga trabalhar com mais de um media type, ele pode informar a ordem de prioridade, colocando o media type preferido primeiro, precedido dos menos importantes, separados por vírgula

Ex: Accept:  application/xml, application/json

Cabe esclarecer que caso o client solicite o recurso em um media type que o servidor não fornece, deverá ser retornada uma resposta com o código 406 Not Acceptable.

Para a implementação proposta, utilizaremos JAX-RS através de sua implementação padrão Jersey.

@Path("/funcionarios")
public class FuncionarioResource {
 @GET
 @Path("{id}")
 @Produces({ "application/xml", "application/json" })
 public Funcionario getFuncionario(@PathParam("id") Integer id) {
  Funcionario funcionario = repository.get(id);
  return funcionario;
 }
}
Serei breve nas explicações das anotações básicas tendo em vista que existem excelentes materiais na web e focarei no necessário para a negociação de conteúdo.

A anotação @Path("/funcionarios") informa a url da nossa RootResource.

Em seguida anotamos nosso método getFuncionario com a anotação @GET que informa que este método aceita apenas requisições feitas pelo método GET do http, isso quer dizer que nosso método é idempotente, não importa quantas vezes a requisição seja feita, ela não alterará o estado do recurso.

Também anotamos o método com @Path("{id}"), informando que devemos passar o id do funcionário na URI.  Para que consigamos acessar o recurso devemos usar o caminho funcionarios/1 por exemplo.

Como parâmetro o método espera o id do funcionário. Anotamos esse parâmetro com @PathParam("id") para que seja injetado na nossa variável id o valor passado pela URI conforme indicado na anotação @Path("{id}").

Para o assunto tratado a mais importante é a anotação @Produces({"application/xml", "application/json"}), ela informa que este método retorna o nosso recurso tanto em XML quanto JSON dependendo apenas da solicitação do cliente. A implementação JERSEY se responsabiliza em parsear o  recurso para estes formatos então precisamos apenas retornar nosso recurso:  Funcionario funcionario = repository.get(id);

Agora vamos expor nosso recurso como uma imagem. Para isso, precisamos fazer nossa própria implementação, que é transformar nosso recurso em uma imagem. Neste caso vamos usar o atributo caminhoFoto para buscar a foto e retorná-la como um array de bytes.


 @GET
 @Path("{id}")
 @Produces({ "image/jpeg", "image/jpg" })
 public byte[] getPhoto(@PathParam("id") Integer id) {
  Funcionario funcionario = repository.get(1);
  
  try {
   InputStream is = this.getClass().getResourceAsStream(funcionario.getCaminhoFoto());

   BufferedImage img = ImageIO.read(is);

   ByteArrayOutputStream bao = new ByteArrayOutputStream();

   ImageIO.write(img, "jpg", bao);

   return bao.toByteArray();

  } catch (IOException e) {
   throw new RuntimeException(e);
  }
 }

Note que são usadas as mesmas anotações no método getFuncionario e no getFoto, inclusive o @Path é o mesmo. A única diferença é que o método getFoto retorna media types do tipo "image/jpeg" ou "image/jpg".

Como o valor da anotação @Path é o mesmo, oque determina qual método atenderá a requisição é justamente o tipo de media type aceito pelo client.

Caso ele envie uma requisição com Accept: application/xml ou application/json o método getFuncionario será invocado, ou então, caso a requisição possua Accept: image/jpeg ou image/jpg, o método getFoto será invocado.

No meu github tem a implementação completa do projeto que pode ser publicado em qualquer servlet container, desenvolvido com maven.

Espero que o post possa ser útil.

Abrasssss


quarta-feira, 28 de setembro de 2011

Como testar os Controllers do Vraptor com Mockito


Um dos frameworks que mais gosto de trabalhar, devido a sua simplicidade e produtividade é o Vraptor. Uma das suas vantagens é que ele abstrai a complexidade da API de Servlets, NÃO te obriga a trabalhar com getters/setters evitando que seu modelo se torne anêmico. Não é intrusivo, você foca na sua lógica de negócios e não em aprender sobre a arquitetura e classes do framework, ou seja, a curva de aprendizado é minima.

Trabalha de forma muito fácil com injeção de dependência. Não é necessário configurar quase nada. Tem suporte a REST e inumeros outros recursos. Mas oque chama realmente a atenção é que você consegue começar a trabalhar com ele em questão de minutos. Poderiamos ficar o dia todo discutindo sobre as vantagens de utilizar este framework. Portanto vamos ao objetivo do post: Aprender a testar unitáriamente as classes de controller do Vraptor.

Para isso utilizaremos o JUnit e o Mockito.

Desejamos testar o método salva(Aluno aluno) do controller abaixo. Este método recebe um aluno, verifica se é valido, salva e redireciona para a listagem, caso o aluno seja inconsistente ele redireciona para a página de cadastro/edição para exibir os erros.

@Resource
public class AlunoController {
private AlunoRepository alunoRepository;

 private Result result;

 private Validator validator;

 public AlunoController(AlunoRepository alunoRepository, Result result, Validator validator) {
  this.alunoRepository = alunoRepository;
  this.result = result;
  this.validator = validator;
 }

 public void add(Aluno aluno) {
  this.validator.validate(aluno);
  this.validator.onErrorForwardTo(this).cadastra();

  this.alunoRepository.add(aluno);
  this.result.redirectTo(this).lista();
 }
}
Temos como dependência a interface AlunoRepository e como o objetivo é testar o controller, devemos mockar esta dependência.

Criamos uma classe de teste comum do JUnit.

public class AlunoControllerTest {
 private AlunoController controller;

 private AlunoRepository alunoRepository;

 private MockResult result;

 private JSR303MockValidator validator;

 @Before
 public void setUp() throws Exception {
  this.alunoRepository = mock(AlunoRepository.class);

  result = spy(new MockResult());
  validator = spy(new JSR303MockValidator());
  controller = new AlunoController(alunoRepository, turmaRepository, result, validator);
 }
}

Note que os objetos result e validator usam mocks apropriados, portanto não precisamos nos preocupar com eles. É melhor utilizar estes mocks fornecidos, pois estes objetos usam Fluent Interface oque torna sua testabilidade muito difícil.

Repare também que usamos o método spy(T object) para obter as instancias do result e validator, isso é util pois conseguimos chamar os métodos reais dos objetos, então podemos verificar se realmente houveram interações com os objetos.

O teste:

@Test
public void add() {
 Aluno aluno = getAlunoConsistente();
 controller.add(aluno);
 verify(alunoRepository).add(aluno);
}
Através deste teste tentamos salvar um aluno, que é um objeto consistente (válido). Então o aluno deve ser adicionado ao repositório, portanto nos asseguramos que o método add(Aluno aluno) do repositório foi chamado, isso é feito através da linha: verify(alunoRepository).add(aluno);

Para testarmos nossas validações, desenvolvemos um teste que espera que uma ValidationException seja lançada e nos asseguramos que não houveram interações com o repositório:
@Test(expected = ValidationException.class)
public void gravaAlunoInconsistenteTest() {
 controller.grava(getAlunoInconsistente());
 verifyNoMoreInteractions(alunoRepository);
}
Esse post teve origem em uma thread do GUJ que abri e recebi orientações do Lucas Cavalcanti: http://www.guj.com.br/java/243436-vraptor-e-mockito---testes-de-controllers


UPDATE:
Muitas vezes desejamos verificar se o nosso método fez um redirecionamento para uma view ou lógica específica. Então como o Lucas citou, podemos fazer:


AlunoController spy = Mockito.spy(alunoController); 
when(result.redirectTo(alunoController)).thenReturn(spy); 
this.alunoController.grava(aluno); 
verify(spy).lista();

Assim estamos nos assegurando que o método lista() foi chamado, ou seja, foi feito o redirecionamento.

Abraços

quarta-feira, 24 de agosto de 2011

Automatizando testes de aceitação com Selenium

Testar a interface (camada de visualização) de uma aplicação web é uma tarefa trabalhosa, repetitiva e que requer atenção. Na maioria dos projetos a única técnica utilizada é o teste manual: o desenvolvedor abre o navegador, preenche todos os campos manualmente, envia o formulário e então certifica-se que o resultado renderizado é o resultado esperado.

Estes testes devem ser utilizados em todas as interfaces do sistema, porém muitas equipes os ignoram. Em interfaces com poucos campos a serem preenchidos tais testes passam a impressão de que são desnecessários, pois, pode-se testá-las mais rapidamente de forma manual do que escrevendo o teste automatizado.

Entretanto quando o sistema começa crescer e a complexidade das telas aumenta, os testes automatizados pagam seu custo inicial, além de garantir a qualidade do sistema.

O Selenium WebDriver é uma ótima ferramenta para execução de testes de aceitação e será abordado para o desenvolvimento destes testes, neste em outros posts.

Primeiro passo:

Adicione o Selenium em seu classpath. Com o maven basta adicioná-lo como dependência:

<dependency>
	<groupId>org.seleniumhq.selenium</groupId>
	<artifactId>selenium-firefox-driver</artifactId>
	<version>2.4.0</version>
</dependency>

O próximo passo é instanciar um WebDriver:

WebDriver driver = new FirefoxDriver();

WebDriver é uma interface que simula o browser em seu teste. Neste caso instanciamos o FirefoxDriver que permite que o teste seja visualizado.

Existem outras implementações da interface WebDriver, como o HtmlUnit Driver, que permite que o teste seja executado mais rapidamente, porém não é possível visualizar o teste em tela.

Aqui podem ser encontradas as vantagens e desvantagens entre as implementações.

Depois é necessário acessar a url:
driver.get("http://www.meudominio.com.br/aluno/cadastro");

O método get requisita a página e espera que seja totalmente carregada para o
início dos testes.

Com a interface WebElement é possível manipular os valores dos campos, para isso, é necessária uma referência do campo.

Supondo que os campos do cadastro sejam:
<input type="text" name="aluno.nome" />
<input type="text" name="aluno.email" />

A referência pode ser obtida através de uma pesquisa do nome do campo:
WebElement nome = driver.findElement(By.name("aluno.nome"));
WebElement email = driver.findElement(By.name("aluno.email"));

Agora com referências aos elementos, pode-se enviar algum valor para eles:
nome.sendKeys("Renan");
email.sendKeys("renan@renan.com");

Então submetemos o formulário:
email.submit();

Note que chamamos o método submit da instância email. Apesar de email não ser um formulário, o Selenium submete o formulário a que o elemento pertence.

Agora que submetemos o formulário podemos averiguar se o sistema se comportou da forma que esperávamos.

Supomos que o comportamento esperado é exibir a mensagem: "Aluno Renan Cadastrado com sucesso.", dentro de um elemento com o atributo id preenchido como "result".

<div id="result">Aluno Renan Cadastrado com sucesso.</div>

Podemos fazer as asserções para verificar o resultado. Segue um exemplo utilizando JUnit:
Assert.assertEquals("Aluno Renan Cadastrado com sucesso.", result.getText());

Grande abraço.