DESENVOLVENDO PARA ANDROID: NOTIFICAÇÕES.

Opa galera, depois de tanto tempo, estou voltando para escrever um post rápido sobre android. Que são as notificações, lugares onde possam ser armazenados pequenas mensagens de aviso para o usuário.

Para criar uma nova notificação basta dar inicializar a classe Notification. Ela pode receber no construtor uma imagem, texto e o momento em que ela foi criada. Para mais informações consulte a documentação do Android.


Notification notification = new Notification(R.drawable.imagem, message, System.currentTimeMillis());

Ela deve conter a ação no qual ocorrerá quando ela for selecionada. Então ela deve conter uma Intent para saber o que fazer quando isso ocorrer. Um ponto pra ser reparado é o fato de colocar a flag Intent.FLAG_ACTIVITY_NEW_TASK na Intent. Assim ela iniciará uma nova Activity a sua escolha.


Intent notificationIntent = new Intent(ctx, Activity.class);

PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0, notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

A seguir o exemplo completo:


Notification notification = new Notification(R.drawable.imagem, message, System.currentTimeMillis());

 

Intent notificationIntent = new Intent(ctx, Activity.class);

PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0, notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

 

//Aqui adicionamos o efeito de vibrar ao adicionar a notificação. Lembrando que para isso, precisamos adicionar a permissão:

//<uses-permission android:name="android.permission.VIBRATE"></uses-permission> no AndroidManifest.xml

notification.defaults |= Notification.DEFAULT_VIBRATE;

long[] vibrate = {0,100,200,300};

notification.vibrate = vibrate;

&nbsp;

//Aqui estamos setando o título para a notificação e o texto que será exibido

notification.setLatestEventInfo(ctx, "Título", message, contentIntent);

&nbsp;

//Aqui estamos configurando o controle das notificações. Para isso você pega um serviço do sistema

NotificationManager manager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);

//Então é só exibir a notificação pronta no sistema

manager.notify(idNoty, notification);

REFACTORING – Caso Real e boas maneiras Parte IV (Keep Walking…)

Essa semana tive que resolver um bug na feature dos posts anteriores. Acabei esquecendo um caso que caia em uma Exception, mas não vamos tocar no assunto :).

O caso é o seguinte, como dito anteriormente, aconteceu que eu tive que manter esse código, corrigir a falha como dito anteriormente e porque não refatorar mais um pouco?

E o caso da refactoring de hoje, tem um tema central que é o uso excessivo de getters e setters (aquele mesmo que você usa, não sabe o porque, e todo mundo acha que está certo. Amém.).

Um amigo meu defende: “porque usar todos os atributos privados, se tem um método get e set para cada. Usa todos os atributos públicos e pronto. Muito mais elegante”. Bem, eu concordo e não concordo. O uso excessivo de getters e setters, no qual eu já defendi como correto(#fail pra mim), é prejudicial. Mesmo se você não precise, e não saiba o porque, você vai criar um. As vezes por costume, ou o framework usado no seu projeto obrigue. Mas enfim, vamos usá-los quando preciso, respeitando o encapsulamento. Fundamento da OO muitas vezes esquecido.

Então, como fazer? Como diz o Guilherme Silveira na palestra sobre design de código. No meu código, eu tenho um objeto que sempre terá um atributo. O que eu faço para que esse meu objeto sempre tenha esse atributo ao criá-lo? Colocar no construtor? Muito bem, é isso mesmo. Adicionando os atributos no construtor, muito dos setters serão inúteis, então só deletá-los.

Pois então vemos como ficou o nosso código. Focando no método carregar a lista de objetos para o relatório.

Repare em todos os setters que estão listados para “montar” o objeto, para então ser passado a lista. Repare que sempre eu passo mais um objeto do tipo ProdutividadeFisioterapeuta como parâmetro nos métodos, algo está errado. Enquanto na classe ProdutividadeFisioterapeuta.java está o clássico construtor sem parâmetros, chamando o método super() da classe Object. E repleta de getters e setters. Não vou listar a classe, mas acredite, eles estarão lá.

Pois então, vamos criar nosso construtor inteligente na classe ProdutividadeFisioterapeuta.java.

Perceba a clareza que ficou o nosso construtor em relação a bagunça anterior.

Vamos ver como ficou o método da listagem 1, após a refatoração.

Indo pro histórico do github, vemos ai o resultado. 42 linhas a menos e mais clareza no código.

E claro ia esquecendo do mais importante, retirar os setters inúteis. Após excluir os setters, substituí em outros locais do código onde eu os utilizava, como nos testes de integração da classe. Após o último commit:

Finalizando, como tenho dito, sempre você vai ter que manter seu código e se possível sempre tente melhorá-lo. Talvez um dia você olhe para o código e não encontre nada para melhorá-lo. Bem, eu nunca tive esse privilégio. Então é isso, mais um caso prático de como melhorar seu código. Excelente dica: Como não aprender OO com java. Excelente post da caelum.

Até mais e bons estudos.

REFACTORING – Caso Real e boas maneiras Parte III (Soluções)

Bem, citamos várias falhas no post anterior. Vamos tentar resolver a replicação da lógica de negócio. Primeiro nossa classe ProdutividadeService.java possui outras responsabilidades além de realizar esses cálculos. Assim ferindo um princípio básico na Orientação a Objeto, o SRP(link) (Single Responsability Principle). Vamos levar toda essa lógica para uma classe apropriada que tenha apenas essa missão.

Coesão ++.

Então, toda essa regra se trata de calcular um intervalo de tempo que irá ser considerado no meu relatório. Então criamos a classe Intervalo.java, onde as regras serão centralizadas. Estamos criando algo novo, então estamos utilizando TDD. A seguir um exemplo de teste implementado na classe IntervaloTest.java.

Listagem 1. Exemplo de método de teste

Claro, para chegar nesse nível de legibilidade não foi de repente. Escrevemos códigos ruins, e melhoramos gradativamente. Todos os passos de refatoração de sua classe vale para testes. Mais pra frente, mostrarei uma boa prática na escrita de testes.

Ao final, temos como resultado a classe Intervalo.java:

Listagem 2.

O método intersecao() será aquele utilizado para calcular o intervalo em si. Para cada if mostrado anteriormente temos um booleano que representa os casos que devem ser levados em conta, consequentemente, os casos abordados pelos testes. Para cada condicional atendido, um novo intervalo será retornado levando em conta a dataInicial e dataFinal coerentes.

Como curiosidade, vemos que com a utilização do TDD, um caso novo foi incluído(o caso de um intervalo não interceptar o outro. Por exemplo, o intervalo usado como referencia for no período de junho e o outro intervalo está em um mês diferente. Retornamos null), e mesmo assim temos menos ifs explicitando cada caso e mesmo assim os testes são atendidos.Dessa forma excluímos código desnecessário, diminuindo ainda mais o número de linhas sem prejudicar no entendimento.

Também não criamos os famosos getters e setters  para cada atributo da classe. Bem, os getters foram utilizados, mas os setters não tivemos necessidade graças ao construtor inteligente da classe.

Encapsulamento ++.

Mas onde a classe intervalo sera usada? Adicionamos na classe CargaHorária.java e Produtividade.java, eles terão um Intervalo (composição).

Todos os métodos replicados serão excluídos:

Listagem 3. Resultado na classe CargaHoraria.java

Método calculaHoras foi movido para a classe CargaHoraria, trazendo a responsabilidade para uma entidade mais apropriada. Mas ainda vemos o que melhorar, como a extensão dos nomes, os métodos doubleValue(), a extensão das listas de parâmentros, mas ainda não acabamos.

Listagem 4. Método calculaHoras.. na classe ProdutividadeService depois da refatoração:

Todo aquele código foi excluído, restando apenas esse trecho. Lindo!

Tirei um print screen com o log do github:

Isso mesmo, 102 linhas de código inúteis a menos, que agora não mais atormentarão. E o sistema ainda fazendo o que deve fazer com testes cobrindo qualquer modificação minha.

A primeira etapa de refatoração concluída, vemos que ganhamos bastante, código desnecessário foi deletado, regra de negócio centralizada, a feiosa cascata de ifs também excluída, algumas renomeações feitas. Mas há ainda o que melhorar.

A utilização de métodos estáticos pra mim soa estranho, quase a OO tem um derrame ao utilizer esses métodos ditos genéricos, que nós criamos. Para isso vamos extrair o método de calculo de Dias em um Período, da classe DataUtil.java, para a classeIntervalo.java.


Double numeroDeDias = intersecao.getQuantidadeVezesOsDiasDaSemanaApareceramNoPeriodo(capturaDiasDaSemana()).doubleValue()

Integer aparicoesNoIntervalo(List<DiaDaSemana> dias);

Ok, mas dando uma olhada no método calculaHoras() na classe CargaHorária.java,  se eu tenho duas propriedades da classe interseção passadas como parâmetro, porque não levar esse método para a classe Interseção. Já resolve o problema da longa lista de parâmetros, prejudicial na legibilidade do método. Além do método capturaDias(), além de não dizer nada, percebeu que ele era inútil, olhe que maravilha, mais código desnecessário excluído.

Listagem 5. Método calculaHoras.. na classe ProdutividadeService.java

Mais algumas renomeações e extrações, percebemos que se tornaria ainda mais legível, levar o método calculaHoras() para Produtividade.java. A responsabilidade de calcular horas realmente deve ser dessa entidade. Um simples cast resolveu aqueles métodos doubleValue().

Design ++.

E por fim, não basta refatorar a classe, os testes terão que ser mantidos. Uma olhada nessa bizarrice feita por mim.

Nunca é legal você entupir os métodos com asserts. Reduza o número deles, assim você diminui a responsabilidade de cada método de teste e modularize seus testes, cada um testando determinada unidade de código.

Mas como fazer? Ai aparece uma prática simples, em que eu particularmente dava valor: Sobrescreva o equals() e o hashCode(). Olha que maravilha. Ao invés de criar uma assertiva para cada atributo do objeto. Crie um objeto com os resultados esperados. Assim apenas um assert é criado, realizando todos os comparativos feitos acima. Código a seguir:

OBS: Pra quem estreanhou, eu estar falando de Funcionário e depois apareceu Fisioterapeuta.Mude apenas a nomenclatura. Eu estava tentando generalizar os exemplos mas espero que não tenha prejudicado o entendimento. Qualquer coisa mandem feedbacks.

Link para a parte I.

Link para a parte II.

Abraço pessoal. Bons estudos e espero ter compartilhado uma experiência bacana.

REFACTORING – Caso Real e Boas Maneiras: Parte II (Bad Smells)

Para começar, não vou citar uma receita de bolo, mas esses três passos já são um começo para que você refatore sem medo.

I)              Entenda sua regra de negócio: Pelo o que tenho notado, essa etapa não é dita na maioria dos tutoriais e livros, mas pra mim é de suma importância. Como você vai implementar algo em que não conhece ou o conceito não esteja “no sangue”? Bem, o Diniz fala que não tem problema, apenas ele vai levar um tempo maior para resolver o problema. Enfim, eu acho uma etapa importante, pois o raciocínio fluirá mais facilmente e não será preciso muitas voltas para resolver o problema.

II)            Crie testes automatizados para o seu código legado.

III)          Se for necessário criar algo novo,  use TDD.

IV)          REFATORE!

Então, temos os passos, vamos entender nosso problema.

I) Regra de Negócio. O código foi retirado de um sistema que já está em produção, portando é um código verídico(sim, eu consegui fazer!). Eu devia popular um objeto para ele ser repassado para um relatório que calcularia a produtividade de um funcionário. Basicamente é isso. E um dos campos seria preenchido com o valor  de horas da carga horária desse funcionário no intervalo escolhido pelo usuário.

 

Explicando de novo: Eu tenho uma referência de tempo fixa, escolhida pelo usuário que emitiria o relatório. A partir daí eu tenho um intervalo que será considerado, intervalo esse que será calculado a partir do período que é a carga horaria do funcionário. Ufa! Acho que deu pra entender.

Listagem 1.

Kent Back, fala sobre bad smells no seu código referindo a qualquer perda de legibilidade e design no seu código. De cara podemos citar vários. Listaremos alguns mais relevantes. E no próximo tópico, citarei práticas para corrigir esses “fedores”.

Eu lembro que quando revisaram esse código, eu ouvi “nossa mãe do céu!”. Pensei então: “a casa caiu”. E realmente esse não foi uma das minhas melhores performances.

Tá, mas o que diabos é essa cascata de ifs? Somente esse erro, ja desencadeia várias más praticas(e essa ganha de goleada.).  Com isso, vemos a lógica replicada 7 vezes , uma para cada caso que a carga horaria se encaixa no período referencia. Vemos a padronização dos parâmetros em que cada método recebe. São exatamente os mesmos, mudando apenas o comportamento interno entre eles.

Com isso temos um método com um tamanho grande, e na listagem 2, vemos a implementação dos 7 métodos, responsáveis pelos cálculos. E na listagem 3, vemos os métodos verificadores na classe CargaHoraria.java. Da mesma forma, também replicados. Juntando métodos replicados, com um método central que invoca os demais, temos como um resultado uma classe quilométrica. E quem gosta de manter uma classe desse tipo? Imagine que o cálculo precisa de uma pequena modificação. Pois é, temos que corrigir os 7 métodos.

Listagem 2

Dando continuidade, o Guilherme Silveira diz na sua palestra sobre Design de Código, que qualquer código que não caiba na resolução normal do monitor não merece respeito. E exatamente isso acontece, vemos nomes de métodos talvez explicativos até demais, tornando excessivamente extenso. Esses erros ocorrem na listagem 1 e 2.  Como por exemplo o método  DataUtil.getQuantidadeVezesOsDiasDaSemanaApareceramNoPeriodo(produtividadeDTO.getDtInicial(), produtividadeDTO.getDtFinal(), parseList(cargaHoraria, diasList)).doubleValue();

Listagem 3

Aqui merece um sono WTF! Que o Martin cita no inicio do livro clean code. E além de tudo, o método doubleValue() ainda é chamado pra tornar ainda mais feio. Mas calma, posteriormente mostrarei soluções.

II) Testes Automatizados: Já escrevi uma série de posts sobre testes(links), e pela web está repleta de material sobre o assunto. Então, qual garantia que eu tenho de alterar meu código, e ao final da refatoração ele está ainda fazendo o que eu acho que ele deve fazer? Testes baby! Abuse dos testes e verifique se o código que irá ser refatorado possui testes cobrindo as funcionalidades.

III) E então eu preciso adicionar uma funcionalidade nova. Ai que está o problema. Como eu vou fazer isso? Para garantir faça TDD. A Web também está repleta de material sobre o assunto. Pelo menos para você ganhar embasamento teórico. Pois, da teoria para a prática a distância é muito grande. E para você ter um aproveitamento maior, faça Pair Programming, prática do XP.  Foi a partir de um PP que a idéia desse post saiu. E minha maior sorte o me pair era bem mais experiente que eu, então o aprendizado foi muito grande. Recomendo essa técnica.

IV) Fica para o próximo post, onde apontarei soluções.

Link para a parte 1.

REFACTORING – Caso Real e boas maneiras Parte I (Intro)

1)        INTRO

A Engenharia de Software tradicional, ou pelo menos eu a chamo assim(aquela em que eu dormi muito nas aulas da faculdade), possui toda a uma divisão impecável de processos de software, quase todos aparentado uma linha de montagem do século XIX. Sendo alguns modelos mais conhecidos do que outros. Citando o modelo waterfall, vemos bem evidente a linha de montagem. Cada etapa do modelo, projeto, desenvolvimento, testes, etc. Ocorria ao término da anterior, sempre ocorrendo essa dependência.

Pois bem, os tempos mudaram, e com eles as novas metodologias de desenvolvimento de software despontaram no mercado.  Com todo “jeitão” interativo-incremental de ser. Afim de combater os modelos engessados citados anteriormente.

Mas o post não tem como objetivo discutir as vantagens de uma ou de outra, desvantagens e assim por diante.  Muito menos ter aquelas discussões filosóficas (métodos ágeis #win e pronto! :D ). E sim trazer uma preocupação que com o advento desses novos métodos fica muito mais evidente, que é a manutenção do código.

Não temos mais etapas bem definidas no desenvolvimento, muito menos naquele ciclo de vida do software. Aquele que diz que 70% do tempo de vida do seu software irá ser dedicado a manutenção.  Óbvio que não faço idéia de porcentagem exata. Mas veja bem, a cada momento que você revisa um código, feito por você ou não, a qualquer momento e em qualquer Sprint, mil perdãos amigos, mas vocês estão dando manutenção. E com essa tarefa cada vez mais em evidência, vemos a importância de tratarmos bem esse código, afinal de contas será você, seu colega de trabalho ou algum conhecido que irá encará-lo posteriormente e NÃO um  DAMMIT FREAK  COMPUTER .

Faremos algumas técnicas de Refactoring, em um código ruim(feito por mim), identificaremos “bad smells” e corrigiremos passo a passo, seguindo duas principais fontes. Refactoring – Improving The Design Of Existing Code, Martin Fowler e Clean Code: A Handbook of Agile Software Craftsmanship, Robert Martin.

E claro agradecer meu amigo @marceloemanoel, que sem ele, esse post não sairia.

 

2)         Refactoring

O termo refactoring possui muitas definições. Mas segundo Martin Fowler: Refatoração é uma mudança feita na estrutura interna do software para torná-lo mais fácil de entender e mais barato realizar qualquer mudança sem modificar o comportamento externo do sistema. Além de ser uma fonte chave no post, achei essa a melhor definição.  Bem ao final do post desejo ter demonstrado algumas práticas.

2.1) Porque refatorar?

Para responder essa perguntar vou ser bastante sucinto.  Você refatorando, seu código irá ter um ganho no design. Tendo um melhor design, o código fica mais fácil de ser entendido por GENTE. Sendo mais fácil de ser entendido, os bugs serão mais difíceis de aparecer, e os que já estão “perturbando”, serão achados mais facilmente.

Enfim, citei só o caminho feliz, pois eu creio que essa prática vale realmente a pena. Mas é necessário experiência e conhecimentos principalmente em Orientação a Objeto para chegar a um bom “Refactorer” J.

2.2) Quando refatorar?

Basicamente, sempre que o valor estético do seu código estiver em déficit, prejudicando a clareza e a comunicação.

Mas citando alguns casos aparecem em comum em ambos autores:

  • Código duplicado (duplicated code)
  • Método longo (long method)
  • Classe grande (large class)
  • Lista de parâmetros longa (long parameter list)
  • Má indentação(Bad Indentation)

Para mais detalhes, http://sourcemaking.com/refactoring possui uma síntese dos casos de refatoração extraídos do livro do Fowler.

Próxima etapa, colocaremos a mão na massa, veremos o código problemático e apontaremos os bad smells mais evidentes.

ANDROID: SINCRONIZANDO COM A WEB

Neste Post veremos como sua app android pode se comunicar e obter dados a partir de  algum servidor web.

Essa comunicação é feita utilizando JSON (JavaScript Object Notation), que é uma formatação leve de troca de dados e de fácil manipulação de dados formatados de sua maneira.

Nesse exemplo, que é apenas a captura de um arquivo json retornada pelo servidor, utilizaremos a classe HttpClient para abrir a comunicação. Vamos abrir uma InputStream e com a classe Scanner , receber os dados enviados do servidor e concatenar em uma StringBuffer. Exemplo do método bastante simples “carregaJsonDoServidor” a seguir:


public String carregaJsonDoServidor() throws ClientProtocolException, IOException {

     HttpClient httpClient = new DefaultHttpClient();

     HttpGet httpGet = new HttpGet(encode);

     HttpResponse response = httpClient.execute(httpGet);
     StringBuffer sb = new StringBuffer();

     HttpEntity entity = response.getEntity();

     if (entity != null) {

           Scanner s = new Scanner(entity.getContent());

           s.useDelimiter(",");

           while (s.hasNext()) {

                  sb.append(s.next()).append(",");

            }

      }

      return sb.toString();

}

A Magia dos Testes Automatizados.

A parte final dos três posts falando sobre testes. Vamos ver uma poderosa ferramenta de automação que é o Apache Ant.

O ANT trabalha através de tarefas, que são especificadas através de um arquivo XML chamado buildfile, onde ao editamos este arquivos definindo as tarefas que desejamos que ele faça, como por exemplo:

Criarmos pastas no sistema operacional, pastas que poderemos usar por exemplo para colocar os executáveis da aplicação que estamos desenvolvendo;

Compilarmos recursivamente todos os fontes na pasta dos arquivos fontes de nosso projeto, colocando na pasta dos executáveis;

Copiarmos arquivos, deletarmos arquivos, listarmos arquivos;

Fazer conexões com bancos de dados, utilizarmos comandos do sistema, fazer log de nossos projetos, dentre várias outras tarefas.

O que demonstrarei é como o Ant automatiza tarefas necessárias para que sua aplicação esteja pronta para a implantação, distribuição, etc. Nesse post, abordaremos as seguintes tarefas a serem executadas:

  • Deleção e criação de diretórios.

  • Definir as libs que serão incluídas no projeto.

  • Compilar suas classes.

  • Definir seus testes e executá-los.

  • E o objetivo final, que é gerar o arquivo .war.

Aproveitando a estrutura do projeto já desenvolvido nos outros posts, <link aqui referenciando os posts antigos>vamos criar o arquivo build.xml na raiz do projeto. A estrutura do arquivo xml segue uma estrutura uniforme, mais ou menos dessa forma:

<project name="nome_projeto" basedir="." default="alvo1">

        <target name="alvo1">

             <tarefa1 />

             <tarefa2 />

        </target>

        <target name="alvo2">

              <tarefa1 />

              <tarefa2 />

        </target>

        <target name="alvo3">

              <tarefa1 />

        </target>
</project>
A raiz do arquivo é o elemento project, que possui os atributos name(nome do projeto, ah vá..),basedir(O diretório base a partir do qual os demais caminhos para arquivos e diretórios serão calculados. O “.” se refere ao diretório atual), default(Se você executar o Ant via Terminal e não for especificado nenhum alvo, o alvo declarado aqui será executado).

Os elementos filhos, que são os target, e neles podem possuir uma ou mais tarefas(tasks) a serem executadas (novamente – criar, renomear ou excluir diretórios, compilar e empacotar arquivos, etc. ).

Pois bem, vamos ao “jeitão” do nosso XML. Vamos listar as tarefas que serão executadas e algumas particularidades:

1.Declaro meu classpath (as libs que serão utilizadas no meu projeto).
<path id="classpath">
        <pathelement location="${classes.dir}" />
        <fileset dir="${lib.root}">
              <include name="*.jar" />
        </fileset>
</path>
2.Target, ele exclui o diretório que é criado pelo ant (target). E serão recriados os diretorios onde serão armazenados as classes compiladas e os testes compilados, respectivamente.
<target name="clean">
      <delete dir="${target.dir}"/>
      <mkdir dir="${classes.dir}"/>
      <mkdir dir="${test.classes.dir}"/>
</target>
3. Target, as classes e os testes serão compilados e “jogados” para seus respectivos diretórios, que foram criados no target anterior.
<target name="compile" depends="clean">
        <javac srcdir="${basedir}" destdir="${classes.dir}" >
         <classpath>
            <path refid="classpath"/>
         </classpath>
        </javac>
     <!-- Compila Test classes -->
        <javac destdir="${test.classes.dir}" srcdir="${test.source.dir}">
      <classpath>
              <path refid="classpath"/>
      </classpath>
        </javac>
</target>
4.Próximo target, onde será executado os testes. O Ant gerará um relatório, no formato que você definir na tag “formatter”, armazenando em algum diretório de sua preferência. Adicionamos o classpath novamente e definimos o batchtest (no qual todas as classes com o padrão **/**Teste.java, serão reconhecidas como classe de teste e executadas como tal).
<target name="teste" depends="test-mysql">
        <mkdir dir="${test.report.dir}"/>
        <junit printsummary="on" fork="no" haltonfailure="true" haltonerror="true">
              <sysproperty key="basedir" value="." />
              <formatter type="xml" />
              <classpath refid="classpath"/>
              <batchtest todir="${test.report.dir}">
                    <!-- Unit Tests -->
                    <fileset dir="${test.source.dir}/unit">
                           <include name="${test.source.dir}/unit/${test.pattern}" />
                    </fileset>
                    <!-- Integration Tests -->
                    <fileset dir="${test.source.dir}/integration">
                           <include name="${test.source.dir}/integration/${test.pattern}" />
                    </fileset></p>

              </batchtest>
       </junit>
</target>
5.Por fim, se todas as etapas forem construídas sem erros e os testes passarem, então criaremos o arquivo .war para realizar o deploy no servidor.
<target name="buildwar" depends="teste">
         <javac srcdir="${basedir}" destdir="${classes.dir}">
               <classpath refid="classpath"/>
         </javac>

         <mkdir dir="${war.dir}" />
         <war destfile="${war.dir}/VRaptorTestesAutomatizados.war" webxml="${web.xml}">
              <classes dir="${classes.dir}" />
              <lib dir="${lib.root}"></lib>
              <fileset dir="WebRoot/">
                   <include name="META-INF/**"/>
                   <include name="*.jsp" />
                   <include name="*.html" />
              </fileset>
         </war>
</target>
*Todos os caminhos ${alguma-coisa} está definido no arquivo build.properties, definido na segunda linha.
Rodando o seu script Buildfile, vamos ao resultado no console:
E ao final, como prova que realmente você fez o que tinha que fazer :). Fiz o deploy no servidor e vamos ao resultado no browser.
Sinal que sua aplicação deu certo. Compilamos nossas classes, fazemos nossos testes e geramos nosso .war. Isso é só um pouco que essa poderosa ferramenta, que é o Ant pode fazer. Até os próximos posts.
Seguir

Obtenha todo post novo entregue na sua caixa de entrada.