Os programadores de hoje utilizam cada vez mais práticas ágeis no seu trabalho quotidiano. Mesmo os projectos que seguem o ciclo de vida de desenvolvimento de software padrão podem beneficiar da sua adaptação. Os testes automáticos e o TDD trouxeram mais confiança ao nosso trabalho, facilitaram a implementação de modificações nas funcionalidades existentes e conduziram-nos frequentemente a uma melhor conceção do código. Mas agora não é suficiente. Temos de levar os benefícios dos testes ao limite e o BDD permite-nos fazê-lo. O BDD baseia-se no TDD e acrescenta muito valor às suas práticas. Traz uma linguagem ubíqua para o projeto e permite uma melhor comunicação entre o cliente e os programadores. Oferece muito aos gestores e líderes de projeto, mas também torna a vida de um programador muito mais fácil. Seguir os princípios do BDD dá-nos requisitos claros, os testes são mais fáceis de compreender e podem servir de documentação. O BDD muda o foco dos assuntos de teste e dá-nos a confiança de que testamos o que deveríamos estar a testar - o comportamento.
Se utiliza o TDD, começar com o BDD será fácil - é basicamente um conjunto de boas práticas para o mesmo. O BDD tem um conjunto de regras simples, que dizem como escrever as especificações e o que testar. As especificações são divididas em três partes: Dado (definição das condições de teste), Quando (invocação da ação no sujeito) e Então (asserções). Os testes devem ter nomes descritivos e as estruturas de teste existentes permitem a utilização de métodos e afirmações semelhantes à linguagem natural - tudo isto combinado dá nós testes que sejam legíveis tanto para utilizadores técnicos como não técnicos. Boas convenções de nomenclatura são úteis durante os testes de regressão.
O BDD vem também com um conjunto de diretrizes para os objectos de teste. Em contraste com o TDD, muda o foco do teste da implementação para o teste do comportamento - e a sua utilização conduz a um melhor design e dá mais flexibilidade quando é necessário introduzir alterações. As especificações devem ser como requisitos do cliente escritos e executáveis - as de alto nível devem atuar como testes de aceitação. O objetivo é escrever testes de forma a que seja necessário alterá-los apenas quando os requisitos mudam. A utilização do BDD dá-nos a certeza de que estamos a testar o que realmente precisa de ser testado e é uma abordagem mais pragmática do que o TDD.
Se quiser ver o BDD em ação, recomendamos Rubi. É uma linguagem poderosa e divertida de utilizar e tem um excelente conjunto de ferramentas BDD.
Pepino
Cucumber é o framework mais popular para BDD em Ruby. Introduz uma linguagem especial, chamada Gherkin, na qual escreverá os seus testes. Em contraste com o RSpec, as funcionalidades descritas no Gherkin são texto simples, não códigoe, como tal, pode - e deve - ser compreendida por qualquer pessoa, nomeadamente o cliente.
A funcionalidade do Cucumber tem o seguinte aspeto (exemplo retirado da wiki do Cucumber):
Caraterística: Um texto conciso mas descritivo do que se pretende
Descrição textual do valor comercial desta caraterística
Regras de negócio que regem o âmbito da caraterística
Quaisquer informações adicionais que facilitem a compreensão da caraterística
Cenário: Uma situação comercial determinável
Dada uma condição prévia
E outra condição prévia
Quando uma ação do ator
E outra ação
E ainda outra ação
Então, um resultado testável é alcançado
E algo mais que podemos verificar também acontece
Cenário: Uma situação diferente
...
As caraterísticas serão descritas mais tarde em pormenor.
Utilização do Cucumber no Ruby on Rails
Instalação
Primeiro passo para utilizar o pepino na sua projeto está a instalá-lo. Basta adicionar estas duas gemas ao seu Gemfile:
grupo :test do
gem 'cucumber-rails', :require => false
gem 'database_cleaner'
fim
Agrupe-os executando instalação do pacotee gerar scripts e diretórios Cucumber com o seguinte comando:
Isto irá criar config/cucumber.yml, script/cucumber e caraterísticas/ diretório, que conterá .caraterística bem como definições de passos e ficheiros de suporte. Para executar as suas funcionalidades, utilize um novo comando rake:
ancinho de pepino
Caraterísticas
Vamos analisar melhor as funcionalidades. Uma caraterística é algo que a sua aplicação tem ou faz - por exemplo, envia periodicamente uma newsletter ou permite que o utilizador partilhe as suas fotografias publicamente. Uma funcionalidade consiste em vários cenários, que descrevem o modo como esta funcionalidade funciona em diferentes contextos.
Para demonstrar o uso básico do Cucumber no Rails, vamos escrever uma funcionalidade do zero. Esta funcionalidade de exemplo será a primeira que escreveremos na aplicação, que será mostrada na segunda parte deste artigo. Esta aplicação permitirá ao utilizador criar artigos e lojas (as lojas vendem artigos) e depois criar listas de compras.
Na versão mais simples, depois de compilar a lista de compras, a aplicação mostrará em que lojas os artigos que o utilizador pretende são mais baratos.
Primeiro, crie um novo ficheiro com o nome criar_item.caraterística no caraterísticas/ diretório. No topo de um .caraterística existe um ficheiro Caraterística palavra-chave, seguida de uma breve descrição da mesma. Por exemplo:
Funcionalidade: Criação de itens
Nas linhas seguintes, pode escrever um objetivo de negócio que irá implementar esta funcionalidade. Uma vez que o Cucumber ignora o texto escrito antes do primeiro cenário, não é necessário escrever nada, mas é sem dúvida uma boa ideia.
Para criar facilmente listas de compras com artigos vendidos em lojas próximas
Como utilizador
Quero adicionar artigos ao sistema
No snippet, pode ver um padrão bastante popular acima, com o qual pode descrever objectivos comerciais. É composto por três partes: porque é que a funcionalidade é necessária, quem a quer e o que é. É claro que não tem de seguir este formato, mas não se esqueça de incluir respostas a estas três perguntas na sua descrição.
Cenários
De seguida, escrevemos alguns cenários. Cada cenário começa com a palavra-chave "Cenário" e contém várias etapas.
Cenário: criar um item único
Dado que existe um item "Leite
Quando vou à página principal
E crio o item "Pão".
Depois, vejo "Pão" na lista de itens
Assim, se alguém criou um item chamado Leite, então a criação de Pão é possível e resulta no aparecimento de Pão na lista de itens. Não devemos testar a criação de um registo na base de dados, uma vez que este facto não tem qualquer valor real para o cliente.
Os passos do cenário utilizam três palavras-chave principais:
Dadopara contextualizar o cenário
Quando, para descrever acções
Depois, para a descrição dos resultados
É importante notar que o Cucumber ignora a palavra-chave step com que começa e corresponde apenas à parte posterior. Assim, pode começar os seus passos com "And" onde quer que pareça natural. A única regra para escolher a palavra-chave correta é que o Cenário deve ser facilmente compreendido.
Definições das etapas
A execução do Cucumber produz agora este resultado:
[...]
Funcionalidade: Criar artigos
Para criar facilmente Listas de Compras com Artigos vendidos em Lojas próximas
Como utilizador
Quero adicionar artigos ao sistema
Cenário: criar um item único # features/create_item.feature:6
Dado que existe um item "Leite" # features/create_item.feature:7
Passo indefinido: "existe um Item "Leite"" (Cucumber::Undefined)
[...]
Isto deve-se ao facto de o Cucumber não saber o que queremos dizer quando dizemos "existe um Item de Leite". Para dar algum significado aos seus passos, precisa de os definir em definições_de_etapas diretório.
Uma forma recomendada de organizar as definições das etapas é dividi-las por domínio. Por exemplo, a maioria das etapas que criámos pertence ao domínio Item. Assim, devemos criar um ficheiro com o nome step_definitions/item_steps.rb e coloque aí o seguinte código:
Dado "existe um item "$name"" do |name|
Fabricar :item, nome: nome
fim
Quando "Eu crio "$name" Item" do |name|
em "#new_item" do
preencher "Nome", com: nome
clicar em "Criar"
fim
fim
Depois "Vejo "$name" na lista de itens" do |name|
dentro de ".items" do
expect(page).to have_content name
end
fim
As definições das etapas geralmente são baseadas no Capybara. Se não estiver familiarizado com o Capybara, não se esqueça de consultar os links no final deste artigo.
Há mais uma etapa que precisa de ser definida e que não se enquadra nas etapas do item. Poderia colocá-la em main_page_steps.rb:
Quando "Eu vou para a página principal" do
visitar caminho_de_raiz
fim
Conclusão
Esta é uma história muito simples para uma funcionalidade muito simples. O seu objetivo era demonstrar os conceitos fundamentais do BDD tal como são utilizados no Cucumber. No entanto, escrever boas histórias requer um pouco mais. Como programador, terá de mudar completamente a sua mentalidade - esquecer a implementação e concentrar-se nos objectivos de negócio. O Cucumber torna esta transição mais fácil com a sua utilização inteligente de histórias em texto simples.