artigo Automação de Testes de Aceitação com Cucumber e JRuby Aprenda a escrever especificações em linguagem natural executáveis e revolucione a forma como você trabalha e desenvolve aplicações para seus usuários Demetrius Nunes ([email protected]): formado em Engenharia de Computação (PUC-Rio/2000). Em 2004, se apaixonou por Ruby ao usar a linguagem em sua dissertação de mestrado na PUC-Rio. Certificado como ScrumMaster em 2007, no seu dia-a-dia, tenta resolver o máximo de “pepinos” para que os talentosos desenvolvedores do TecGraf/PUC-Rio possam “trabalhar em paz”. 36 www.mundoj.com.br Dois graves problemas crônicos afligem projetos de desenvolvimento de software nos dias de hoje: documentação inexistente ou desatualizada e testes de regressão manuais lentos e ineficientes. Aprenda a se livrar desses dois males com uma só tacada utilizando um processo orientado a testes de aceitação automatizados através da ferramenta Cucumber. "SUJHPt"VUPNBÎÍPEF5FTUFTEF"DFJUBÎÍPDPN$VDVNCFSF+3VCZ M esmo com todo o barulho que se faz atualmente em torno de TDD (Test Driven Development), esta importante prática ainda não é parte da cultura da nossa indústria. É aquela velha história: na hora do aperto, o que importa mesmo é código escrito e rodando, certo? Escrever documentação? Depois a gente faz... Testes de regressão automatizados? A gente dá uma “testadinha” agora pra ver se está tudo bem e depois... Só que o depois nunca chega e assim acumulamos o que chamamos de dívida técnica. O pior é que essa dívida acumulada cobra “juros” pesados e em pouco tempo, o ritmo de desenvolvimento chega àquele ponto em que tudo o que a equipe faz é consertar bugs, que por sua vez introduzem novos bugs, gerando um ciclo infindável de “conserta aqui-quebra ali” onde não há mais a menor confiança na qualidade final do produto. Depois de um tempo, a equipe de desenvolvimento não aguenta mais e se rebela, exigindo que a Desenvolvimento orientado a testes de aceitação automatizados Não seria ótimo se ao final de cada iteração (ou “sprint”, assumindo que você utiliza alguma metodologia iterativa, como Scrum) sua equipe de fato entregasse mais um conjunto de funcionalidades, juntamente com toda a documentação (principalmente as especificações funcionais) escrita e atualizada e com testes de aceitação automatizados que comprovam que o que foi implementado realmente está de acordo com o que foi especificado, ou seja, acordado entre você e o usuário? Além disso, não seria maravilhoso que, no apertar de um botão, você conseguisse ver em alguns minutos todo o sistema sendo reexecutado automaticamente, passando por todas as funcionalidades já entregues nas iterações anteriores, provando que nada que já funcionava deixou de funcionar? Sonho, delírio, utopia? Essa visão não só é perfeitamente possível de ser atingida, como deveria ser o padrão mínimo de qualidade e profissionalismo em nossa indústria. Para que isso ocorra, precisamos mudar fundamentalmente a nossa forma de pensar na seguinte direção: o tempo do desenvolvedor não pode e nem deve ser gasto praticamente de forma integral na atividade de codificação de funcionalidades e/ou correções de bugs. Existem outras atividades tão valiosas quanto a codificação que merecem um tempo considerável de dedicação da equipe de desenvolvimento. Colocando de forma geral, essa seria a divisão de gerência permita o famoso “reescrever do zero”. Mas será que dessa vez a história será diferente? Afinal, o problema não foi causado pela própria falta de profissionalismo da equipe? Claro que não! A gerência é que foi a culpada, pois foi ela que concordou com aqueles prazos impossíveis! Ou então foi culpa do usuário, que mudava de ideia a toda hora e só sabia pedir mais e mais funcionalidades inúteis, certo? Talvez sim, talvez não, mas se queremos realmente mudar nossos resultados, temos que começar por nós mesmos, pois para podermos ser de fato considerados profissionais, não podemos abrir mão de todas as práticas e técnicas necessárias para garantir a qualidade do nosso trabalho. Ou você acha que um médico aceitaria não esterilizar seus instrumentos ou deixaria de higienizar suas mãos antes de uma cirurgia por estar sendo pressionado pelo hospital onde trabalha? tempo que considero mais apropriada de acordo com o valor agregado de cada atividade: t OBFMBCPSBÎÍPEFFTQFDJmDBÎÜFTGVODJPOBJTFEPDVNFOUBÎÍP técnica; t OBBVUPNBÎÍPEFUFTUFTEFBDFJUBÎÍPRVFDPNQSPWFNPCPN funcionamento do sistema; t OP EFTJHO F DPEJmDBÎÍP EF GVODJPOBMJEBEFT F DPSSFÎÜFT EF bugs; t PVUSBTBUJWJEBEFT Você pode estar se perguntando se gastar um quarto do tempo da equipe de desenvolvimento elaborando especificações funcionais realmente vale a pena, pois pela nossa experiência, sabemos que no exato segundo em que terminamos de escrever uma especificação, ela já está desatualizada e vai ficando cada vez mais desatualizada conforme o sistema vai evoluindo e mudando. Afinal, quem tem tempo de ficar atualizando todas as especificações já escritas cada vez que o cliente muda de ideia sobre como o sistema deve funcionar? E quanto a mais 25% em automação de testes de aceitação? Não basta rodar o sistema manualmente e ver que ele funciona de acordo com o que foi especificado? Gastar metade do tempo da equipe realizando essas atividades parece loucura, mas na verdade loucura é justamente não realizá-las, pois são justamente essas duas atividades que produzirão as peças-chave para manter o ritmo de desenvolvimento sustentável e a qualidade do siste- 37 "SUJHPt"VUPNBÎÍPEF5FTUFTEF"DFJUBÎÍPDPN$VDVNCFSF+3VCZ ma no longo prazo. Afinal, quem vai garantir que todas as modificações introduzidas na última iteração não afetaram funcionalidades que já haviam sido testadas e entregues? Para piorar, conforme o sistema vai crescendo e se tornando mais complexo, testar novamente todo o sistema de forma manual para garantir que nada deixou de funcionar (a isso denominamos teste de regressão, pois com ele evitamos que o sistema “regrida”) vai adquirindo custos proibitivos até o ponto em que se torna inviável. Especificações funcionais executáveis utilizando Linguagem Gherkin Uma especificação funcional escrita de forma tradicional, como, por exemplo, um documento de texto estático, tem um valor agregado limitado, que como vimos acima, vai se depreciando conforme o sistema evolui. Mas e se pudéssemos utilizar nossa especificação funcional ativamente de forma que ela sirva para verificar se o comportamento do sistema está de acordo com o que foi escrito? Idealmente, ao entregar uma funcionalidade nova, deveríamos verificar que ela está perfeitamente aderente ao que foi especificado, certo? Não seria ótimo se pudéssemos automatizar essa verificação, passando este trabalho para a máquina, que poderia executá-la muito mais rapidamente e bem mais frequente? Para fazer isso, basta aprendermos a escrever uma especificação em linguagem “Gherkin”, uma linguagem específica de domínio de negócios (DSL), que podemos chamar de “pseudolinguagem natural”, pois, apesar de aparentar ser um texto livre, ela segue uma estrutura conhecida como visto na Listagem 1. Listagem 1. Estrutura de uma especificação em linguagem Gherkin. Dado que (pré-condição 1) E que (pré-condição 2) Quando (ação 1) E (ação 2) E (ação 3) Então (pós-condição 1) E (pós-condição 2) E (pós-condição 3) As palavras-chave Dado, Quando e Então servem para denominar, respectivamente, pré-condições, ações (ou eventos) e pós-condições (ou expectativas). A conjunção E é apenas um recurso para evitar repetições dessas palavras-chave e tornar o texto mais legível. Vejamos um exemplo prático de uma funcionalidade de autenticação para uma aplicação de ambiente desktop na Listagem 2. O documento acima especifica como a funcionalidade de “Autenticação por senha” deve funcionar. Ao menos, como o cenário de “Login bemsucedido” deve se comportar. Na prática, outros cenários devem ser adicionados para tornar esta especificação realmente completa e abrangente (dependendo de nossos requisitos, poderíamos ter outros cenários, como, por exemplo: login malsucedido, campos não-preenchidos, usuários desativados etc.). O texto entre Funcionalidade e Cenário é apenas uma narrativa no formato de “User Story” (Para que, Como, Eu quero) e serve apenas para tornar o documento mais compreensível, como um cabeçalho. A linha “# language: pt” servirá para informar ao Cucumber que a especificação está em português. O comportamento do sistema é especificado de fato 38 www.mundoj.com.br Listagem 2. Especificação para uma funcionalidade de Login em um sistema desktop. # language: pt Funcionalidade: Autenticação por senha Para garantir a segurança das informações do meu sistema Como um usuário cadastrado Eu quero ter que me autenticar com uma senha antes de ter acesso ao sistema Cenário: Login bem-sucedido Dado que estou na tela de Login Quando preencho o campo “Usuário” com “silva” E preencho o campo “Senha” com “segredo” E aperto o botão “Entrar” Então devo ver a tela Principal E devo ver a mensagem “Bem-vindo Sr. Silva!” após o título do Cenário, utilizando a estrutura Gherkin. Note como, apesar de estarmos seguindo uma estrutura gramatical fixa, o texto produzido é perfeitamente compreensível para usuários finais do sistema e pode ser validado por eles antes mesmo de começarmos a escrever qualquer código. Executando especificações Gherkin com Cucumber Para executar as especificações escritas em linguagem Gherkin, utilizaremos a ferramenta de BDD (Behaviour Driven Development) chamada Cucumber (veja como instalar Cucumber no Quadro 1). Cucumber é escrita em linguagem Ruby, mas pode ser utilizada para executar especificações de aplicações escritas em qualquer linguagem, como veremos adiante. Para que Cucumber possa executar as especificações, as mesmas devem ser salvas em arquivos-texto com extensão “.feature”. É aconselhável utilizar a seguinte estrutura de diretórios para isso: $RAIZ_DA_APLICACAO features/ login.feature step_definitions/ support/ Por hora, vamos ignorar as pastas “step_definitions” e “support”, que serão explicadas no próximo tópico. Salvando o conteúdo da Listagem 2 no arquivo “features/login.feature” (lembre-se de salvar o arquivo em formato UTF-8), podemos digitar o comando visto na Listagem 3 numa sessão de terminal a partir do diretório raiz da aplicação para que a especificação em “login.feature” seja executada pelo Cucumber. Obviamente, conforme Listagem 3 houve uma falha ao tentar executar esta especificação neste momento e vamos entender o resultado obtido. Mas, antes, você deve estar se perguntando: como posso querer executar a especificação se não escrevi nenhuma linha de código do sistema ainda? Fizemos isso pois estamos seguindo a filosofia TDD (Test-Driven Development), em que primeiro escrevemos os testes (no nosso caso na forma de especificações) e depois escrevemos o código da aplicação tendo como objetivo único fazer com que os testes passem. Como especificamos o "SUJHPt"VUPNBÎÍPEF5FTUFTEF"DFJUBÎÍPDPN$VDVNCFSF+3VCZ Listagem 3. Resultado da tentativa de executar a especificação pelo Cucumber $ jruby –S cucumber features/login.feature # language: pt Funcionalidade: Autenticação por senha Para garantir a segurança das informações do meu sistema Como um usuário cadastrado Eu quero ter que me autenticar com uma senha antes de ter acesso ao sistema Cenário: Login bem sucedido # features/login.feature:7 Dado que estou na tela de Login # features/login.feature:8 Quando preencho o campo “Usuário” com “silva” # features/login. feature:9 E preencho o campo “Senha” com “segredo” # features/login. feature:10 E aperto o botão “Entrar” # features/login.feature:11 Então devo ver a tela Principal # features/login.feature:12 E devo ver a mensagem “Bem-vindo Sr. Silva!” # features/login. feature:13 1 scenario (1 undefined) 6 steps (6 undefined) 0m0.027s You can implement step definitions for undefined steps with these snippets: Dado /^que estou na tela de Login$/ do pending end Quando /^preencho o campo “([^\”]*)” com “([^\”]*)”$/ do |arg1, arg2| pending end Quando /^aperto o botão “([^\”]*)”$/ do |arg1| pending end Então /^devo ver a tela Principal$/ do pending end Então /^devo ver a mensagem “([^\”]*)”$/ do |arg1| pending end sistema na forma de exemplos de comportamento (cenários), estamos na verdade praticando BDD (Behaviour Driven Development). Ambas as técnicas possuem resultados e vantagens similares. Mas antes de escrever o código da aplicação, por estarmos escrevendo os testes na forma de especificações em linguagem natural, temos que primeiro dar um passo intermediário: ensinar ao Cucumber como de fato executar os passos contidos no cenário. Fazemos isso “traduzindo” as frases em linguagem natural para comandos em linguagem de programação. Olhando o resultado obtido, vemos que o Cucumber tenta adiantar nosso trabalho fornecendo os pedaços de código em linguagem Ruby que precisamos para ensiná-lo a executar os passos da especificação. O que temos que fazer agora é simplesmente copiar e colar (substitua “Então” por “Entao” quando fizer isso) esses “snippets” dentro de um arquivo com extensão “.rb” dentro da pasta “step_definitions” (por exemplo “step_definitions/login_steps.rb”) e começar a substituir as palavras “pending”, dentro de cada bloco, pelo código que realmente faz o que a frase em linguagem natural está dizendo. Essa é a fase na qual realizamos a automação dos passos. Portanto, o ciclo de desenvolvimento utilizando Cucumber como ferra- menta de BDD segue de forma geral a seguinte sequência: 1. escrevemos a especificação em linguagem natural Gherkin; 2. executamos a especificação e vemos os passos pendentes; 3. traduzimos os passos em linguagem natural pendentes para código executável; 4. executamos a especificação novamente e vemos os passos falharem; 5. escrevemos código da aplicação para fazer os passos passarem; 6. executamos a especificação novamente e vemos os passos passarem; 7. repetimos os passos 2 a 6 até que a especificação passe por completo. Automatizando aplicações Swinger e Jemmy Swing com Para começarmos a traduzir os passos em linguagem natural e implementá-los através de código executável, precisamos de alguma biblioteca ou ferramenta que sirva para simular ações de um usuário no sistema. Para aplicações Web existem muitas opções de ferramentas e bibliotecas para esse fim. Dentre as mais conhecidas estão Selenium, Watir e HtmlUnit. Como especificamos um sistema desktop, iremos utilizar a biblioteca Swinger. Swinger é uma biblioteca escrita em JRuby que oferece algumas dezenas de passos e funções já implementados para a automação de aplicações desenvolvidas em Java e Swing. “Por baixo dos panos”, Swinger apoia-se sobre uma excelente biblioteca desenvolvida pela Sun chamada Jemmy, criando uma fina camada de abstração em torno desta. Jemmy é amplamente utilizada para automatizar os testes da IDE Netbeans, entre outros projetos complexos. A biblioteca Jemmy realiza duas funções básicas de forma bastante eficiente e elegante: permite encontrar qualquer componente Swing em uma aplicação em execução sem que seja necessário o conhecimento do código interno da aplicação e permite manipular estes componentes como se fosse o próprio usuário a fazê-lo. Mesmo que você não utilize JRuby, Cucumber ou Swinger, aconselho fortemente a estudar esta biblioteca para qualquer necessidade de automação de testes de aplicações Swing. Para que possamos automatizar nossa aplicação através de Swinger, primeiro precisamos criar o ambiente de execução e carregar as bibliotecas de apoio necessárias. Para isso, devemos criar dentro da pasta "support" um arquivo chamado "env.rb". Cucumber sempre procura por este arquivo e ele é o primeiro código a ser executado antes das especificações. A primeira linha da Listagem 4 carrega a biblioteca Test::Unit, equivalente ao JUnit no mundo Ruby, para que possamos utilizar assertivas em nossos passos de pós-condição do tipo "Então". A segunda linha carrega a biblioteca Swinger. A terceira linha carrega o sistema a ser testado. A linha "World(Test::Unit::Assertions)" garante que os comandos de assertivas estarão disponíveis como funções globais para implementação dos passos. O bloco "Before do" chama a função "main" de nossa aplicação antes de cada cenário para que a aplicação seja de fato executada. Finalmente, o bloco "After do" fecha a janela que ainda estiver aberta após o término da execução de nossos cenários. Com essa preparação básica do ambiente de execução das especificações, estamos prontos para implementar os passos de automação no nossos sistema no arquivo 'step_definitions/login_steps.rb'. 39 "SUJHPt"VUPNBÎÍPEF5FTUFTEF"DFJUBÎÍPDPN$VDVNCFSF+3VCZ Listagem 4. Preparando o ambiente de execução das especificações no arquivo support/env.rb. require ‘test/unit’ require File.dirname(__FILE__) + ‘/../../lib/swinger/lib/swinger’ require File.dirname(__FILE__) + ‘/../../dist/sistema.jar’ World(Test::Unit::Assertions) Before do import ‘sistema.Login’ Login.main([].to_java(:string)) end After do @container.close if @container end Utilizando Swinger podemos usar funções de ajuda como dialog, text_ field, button, label e frame para localizar os componentes de interface que precisamos manipular, tornando o código de automação dos passos vistos na Listagem 5 bastante simples e rápido de implementar. Listagem 5. Passos automatizados utilizando funções de ajuda do Swinger Dado /^que estou na tela de Login$/ do @container = dialog(“Login”) end Quando /^preencho o campo “([^\”]*)” com “([^\”]*)”$/ do |campo, valor| field = text_field(campo) field.text = valor end Quando /^aperto o botão “([^\”]*)”$/ do |botao| button = button(botao) button.push end Entao /^devo ver a tela Principal$/ do @container = frame(“Principal”) assert @container.visible? end Entao /^devo ver a mensagem “([^\”]*)”$/ do |mensagem| label = label(mensagem) assert label.visible? end Instalando e utilizando Cucumber com JRuby Para ter um ambiente em JRuby e Cucumber funcionando na sua máquina, é muito fácil, basta seguir os cinco passos a seguir: 1. Certifique-se que você possui o interpretador de Java no seu PATH e que ele seja a versão 1.5 ou acima. Para isso, execute o seguinte comando: java –version. 2. Visite o site oficial de JRuby em jruby.org e faça o download da última versão oficial. No momento do fechamento desta edição, era a 1.3.1, mas a 1.4 estava prestes a ser lançada, qualquer uma servirá. 3. Extraia o JRuby para seu disco e adicione o subdiretório bin ao seu PATH. Depois disto, execute o comando abaixo para se certificar que tudo está funcionando: jruby -v 4. Agora precisamos instalar Cucumber através do comando: jruby -S gem install cucumber 5. Pronto! Para executar especificações de um projeto, utilize o comando: jruby -S cucumber <diretorio ou arquivo .feature> Quadro 1. Como instalar Cucumber e JRuby Implementando passos em Cucumber escritos em Java e outras linguagens Eu adoro a linguagem Ruby por todo seu poder e elegância e recomendo fortemente que você invista o tempo para aprendê-la (ainda mais com a possibilidade de poder utilizá-la em cima da JVM através de JRuby). Eu garanto que você irá se apaixonar ou ao menos adotá-la como sua 2ª linguagem (depois de Java, claro). package cukes; Mas se Ruby ainda te assusta, não se preocupe, é possível aproveitar os benefícios da ferramenta Cucumber utilizando apenas a linguagem Java (ou outra linguagem que possa ser executada na JVM, tais como Groovy, Scala, Javascript etc.). Para isso, visite a página do projeto Cuke4Duke em: public class BellySteps { private List<String> belly = new ArrayList<String>(); import cuke4duke.Given; import java.util.List; import java.util.ArrayList; @Given(“eu tenho (\\d+) pepinos na minha barriga”) public void bellyCukes(int cukes) { for(int i = 0; i < cukes; i++) { belly.add(“cukes”); } } http://wiki.github.com/aslakhellesoy/cuke4duke Veja um exemplo de implementação de um passo em Java: } Quadro 2. Não precisa saber Ruby para utilizar Cucumber. 40 www.mundoj.com.br "SUJHPt"VUPNBÎÍPEF5FTUFTEF"DFJUBÎÍPDPN$VDVNCFSF+3VCZ Repare que ainda não escrevemos nenhuma linha de código do nosso sistema, mas já escrevemos o código de teste que irá utilizá-lo. Com isso, fizemos um exercício de imaginar (ou projetar) a interface e as interações do usuário com nosso sistema, o que torna bem mais fácil o processo de implementar o sistema de fato. O código-fonte do sistema em si é bastante simples para este exemplo e fica aqui o exercício para o leitor fazer o download deste projeto a partir do link listado na seção de referências e examiná-lo, além de poder executar as especificações do sistema em seu próprio ambiente e vê-las passar. Mesmo com essas vantagens apontadas, você pode se perguntar se vale realmente a pena investir o tempo necessário para escrever as especificações utilizando a linguagem Gherkin e, principalmente, automatizar cada passo descrito nas especificações. Outra vantagem não mencionada acima e que aparece no médio e longo prazo é que conforme as primeiras especificações são automatizadas, o custo de automação das próximas vai diminuindo, tendendo a praticamente zero. Isso ocorre porque o vocabulário para descrever comportamentos em um sistema é mais limitado do que imaginamos e com o tempo, os passos e suas respectivas automações são reutilizados quase integralmente se assim desejarmos. Portanto, acredite, é possível desenvolver sistemas com documentação e testes de regressão automatizados, com velocidade e qualidade. Seus clientes e usuários agradecem! Referências Considerações finais Mesmo tendo usado um exemplo muito simples, implementamos de fato uma funcionalidade de um sistema seguindo nossa proposta de processo orientado por testes de aceitação automatizados, através das especificações executáveis utilizando Cucumber. E isso nos trouxe grandes vantagens sobre um processo de desenvolvimento mais tradicional: 1. teremos feito exatamente o que foi acordado com o usuário e nada mais do que o necessário; 2. teremos documentação atualizada do comportamento do sistema; 3. teremos testes automatizados que garantem a aderência do sistema às especificações e poderão ser executados toda vez que precisarmos realizar testes de regressão Assim, conseguimos atingir sem maiores esforços nosso objetivo que parecia tão “utópico”. EU USO – Nick Sieger Nick Sieger é engenheiro da Engine Yard, trabalhando no JRuby e liderando esforços para tornar a máquina virtual Java uma plataforma de implantação robusta e fácil de utilizar para aplicações web desenvolvidas em Ruby e Rails. Ele criou e ajuda a manter o adaptador JDBC para ActiveRecord que o JRuby on Rails usa para conectividade com bancos de dados, assim como a ferramenta Warbler e a biblioteca JRuby-Rack para o deploy em servidores de aplicação Java. Ele mantém um blog sobre tópicos relacionados com Ruby e JRuby no endereço http://blog.nicksieger.com/. t $ØEJHPGPOUFEPFYFNQMPWPDÐQPEFCBJYBSPDØEJHPGPOUFDPNQMFUPEBBQMJDBÎÍPEFFYFNQMP EFTUFBSUJHPBUSBWÏTEPDPNBOEPBCBJYP²OFDFTTÈSJPUFS(JUIUUQHJUTDNDPN JOTUBMBEP em sua máquina: HJUDMPOFHJUHJUIVCDPNEFNFUSJVTOVOFTDVDVNCFS@NVOEPKHJU Não esqueça de ler e seguir as instruções contidas no arquivo README presente na raiz do projeto. t 3VCZIUUQXXXSVCZMBOHPSHFIUUQSVCZCSPSH t +3VCZIUUQXXXKSVCZPSH t $VDVNCFSIUUQDVLFTJOGP t 4XJOHFSIUUQHJUIVCDPNEFNFUSJVTOVOFTTXJOHFS t 8IBUhTJOBTUPSZ 1PSRVFFDPNPFTDSFWFS6TFS4UPSJFTEFRVBMJEBEF IUUQEBOOPSUIOFU whats-in-a-story t $ØEJHP-JNQPQPS3PCFSU$.BSUJO&E"MGB#PPLT t "VUPNBÎÍP EF CSPXTFST QBSB BQMJDBÎÜFT 8FC 4FMFOJVN IUUQTFMFOJVNIRPSH 8BUJS IUUQXBUJSDPN )UNM6OJU IUUQIUNMVOJUTPVSDFGPSHFOFU F $FMFSJUZ IUUQDFMFSJUZ SVCZGPSHFPSH t /FUCFBOTF+FNNZIUUQXXXOFUCFBOTPSHFIUUQTKFNNZEFWKBWBOFU Saber mais Figura 1. Tela do sistema já implementado segundo as especificações executáveis. Na Edição 36 da Revista Mundoj, apresentamos o artigo "Aplicações Desktop a jato com JRuby e Netbeans", mostrando como construir uma aplicação Java para ambiente Desktop com Swing, utilizando Netbeans, JRuby e o padrão MVP (Model-View-Presenter) para garantir a testabilidade. Para mim, o principal benefício de usar uma ferramenta como RSpec é clareza de intenção. Eu uso exclusivamente RSpec para testar meu projeto open source JRuby-Rack [1]. JRuby-Rack é um projeto que mistura Java e Ruby, então faz sentido utilizar uma ferramenta Ruby para testar ambos visto que existe a necessidade de se testar código Ruby. No entanto, muitos dos benefícios de clareza e expressividade que tenho visto também podem ser aplicados para projetos completamente feitos em Java. 1. A DSL interna do RSpec faz com que seja mais fácil escrever testes que declarem a sua intenção. "Specdoc" fornece acesso a essa intenção numa forma que pode ser compartilhada com pessoas que não estão familiarizadas com o código. 2. Uma linguagem maleável como Ruby faz com que escrever testes compactos seja mais fácil por meio da aplicação do princípio DRY (Don't Repeat Yourself – "não se repita"), o reuso de setup, teardown e lógica de fixture. 3. As características de integração com Java do JRuby, tais como injeção automática de interface, permite que você possa utilizar objetos Ruby como mocks para métodos Java. O Cucumber leva essa clareza a um novo nível através da união dos testes com a documentação. Suas user stories e requisitos, sua documentação, são os testes. Isso permite que você escreva testes juntamente com um cliente ou especialista de domínio (interessado no projeto) que não possua qualquer experiência em programação. Mesmo que você não veja seu projeto adotando Ruby ou RSpec como uma ferramenta de testes, você deve fazer um favor a si mesmo e dar uma olhada no Cucumber, o qual pode ser usado com Java por meio do projeto Cuke4Duke [2]. [1]: http://jruby-rack.kenai.com/ [2]:http://wiki.github.com/aslakhellesoy/cuke4duke 41