
Artigo
Resumo do webinar: BDD e CD com Lisa Crispin
Leia o artigo
Usamos cookies
Usamos cookies para entender como você nos encontrou e melhorar sua experiência. Você pode aceitar ou recusar os cookies de análise. Saiba mais em nossa política de privacidade.
BDD é uma estratégia de desenvolvimento e, mesmo que você não siga essa prática, achamos vantajoso usar o Cucumber (ou uma ferramenta semelhante), porque ele “obriga” você a documentar os testes automatizados antes de implementá-los. É fundamental que esses testes fiquem claros para um usuário que não conhece o comportamento da funcionalidade descrita e que sejam fáceis de manter, para reduzir o custo de mudar os passos de teste.
Esta imagem do Cucumber reflete a ideia de combinar testes automatizados, ter uma documentação viva e, ao mesmo tempo, continuar tendo especificações executáveis. Tudo isso graças à abordagem de usar uma ferramenta como o Cucumber.

Para trabalhar com o Cucumber, você vai precisar destes arquivos:
Para começar, criamos uma pasta no projeto em que vamos salvar as features que vamos escrever em Gherkin. Vamos basear este exemplo em um exercício de BDD em que queremos modelar o comportamento de um caixa eletrônico por meio de funcionalidades em Gherkin, seguindo estas práticas. Suponha que queremos modelar o comportamento de um caixa eletrônico quando queremos sacar dinheiro:
A descrição de um cenário costuma ser escrita assim:
Scenario: Como [usuário concreto] quero [realizar uma ação concreta] para [resultado ou benefício]
O importante é explicar brevemente o que você quer alcançar com o cenário.
Uma forma de começar a escrever a feature pode ser esta:
Feature: Saque de dinheiro
Scenario: Como usuário existente e habilitado do caixa eletrônico, quero fazer um saque para obter dinheiro.
Alguns pontos importantes sobre os feature files:
Em Gherkin, os cenários são exemplos de comportamentos individuais para estabelecer critérios de aceitação, então pode nos interessar escrever vários por funcionalidade para observar resultados diferentes e tornar o teste mais completo (recomenda-se escrever primeiro os cenários positivos). Para descrever os cenários, são usadas as sentenças de Gherkin: Given, When, Then, But e And. O mais importante é que os passos descrevam brevemente o que se quer fazer na funcionalidade, e não como se quer fazer (isso é responsabilidade das step definitions, explicadas mais adiante).
Um exemplo de cenário mal escrito é este:
Given me autentiquei com um cartão habilitado And o saldo disponível na minha conta é positivo And o caixa eletrônico tem dinheiro suficiente And o caixa eletrônico tem papel suficiente para imprimir comprovantes When insiro o cartão no caixa eletrônico And digito no teclado o PIN do meu cartão And pressiono o botão de confirmar o PIN And pressiono o botão ao lado da opção de sacar dinheiro And digito um valor menor ou igual ao meu saldo disponível And pressiono o botão para confirmar o saque And pressiono o botão para imprimir o comprovante
É melhor evitar escrever cenários assim, porque eles ficam muito longos, com muitos detalhes desnecessários, e por isso são mais difíceis de ler e entender. Outra desvantagem de escrevê-los dessa forma é que ficam difíceis de manter.
Esta é uma forma melhor e mais clara de escrever o cenário:
Scenario: Como usuário existente e habilitado do caixa eletrônico, quero fazer um saque para obter dinheiro. Given me autentiquei com um cartão habilitado And o saldo disponível na minha conta é positivo When seleciono a opção de sacar dinheiro And digito um valor menor do que o meu saldo disponível e do que o saldo disponível do caixa eletrônico Then recebo o dinheiro And o valor recebido é descontado do saldo disponível da minha conta And o sistema devolve o cartão automaticamente And o sistema exibe a mensagem de transação concluída
Alguns pontos importantes sobre cenários e passos em Gherkin:
Given cumpro uma pré-condição When executo uma ação Then observo este resultado But não devo conseguir ver este outro resultado
Ao separar as features, a quantidade de arquivos pode ser enorme, então é preciso pensar em como dividir as features em arquivos diferentes. Uma opção popular é ter um arquivo com as features que agrupam tudo o que se refere a um aspecto da aplicação e até organizá-los em diretórios. Em um caso concreto, para um sistema de entretenimento, você poderia ter isto: no primeiro nível, uma pasta “Shows”. Dentro dela, diferentes features, como criar, editar, excluir e tudo o que tem a ver com eles. Assim tudo fica mais organizado e é mais fácil localizar cada coisa e cada teste.
O BDD é parecido com o SBT (Sample Based Testing), no sentido de que busca reduzir ambiguidades mostrando exemplos. Considerando isso, talvez o exemplo anterior ficasse melhor se o levássemos a dados concretos, como no caso a seguir:
Scenario: Como usuário existente e habilitado do caixa eletrônico, quero fazer um saque para obter dinheiro. Given me autentiquei com um cartão habilitado And o saldo disponível na minha conta é de $10,000 And o caixa eletrônico tem $100,000 em dinheiro When seleciono a opção de sacar dinheiro And indico que quero sacar $1,000 Then recebo $1,000 em duas notas de $500 And o saldo da minha conta passa a ser de $9,000 And o caixa eletrônico fica com $99,000 em dinheiro And o sistema devolve o cartão automaticamente And o sistema exibe a mensagem de transação concluída
Uma dúvida muito comum na hora de escrever um cenário é o ponto de vista a ser usado. A pergunta habitual é: devo escrever os cenários em primeira ou em terceira pessoa? O tema é mais complexo do que parece. Os exemplos da documentação oficial do Cucumber usam os dois pontos de vista, então ela não é uma referência exata para resolver o problema. Estes são os argumentos a favor de cada um:
Dan North (considerado o criador do BDD), segundo uma referência que encontramos no Stack Overflow, recomenda o uso da primeira pessoa e, de fato, é o que ele usa para escrever os cenários no seu artigo “Introducing BDD”.
O uso da primeira pessoa permite que o cenário seja coerente com a sua descrição, que, como mencionado, costuma seguir a forma “Como [usuário concreto] quero [realizar uma ação concreta] para [resultado ou benefício]”.
Como o papel ou usuário específico para o qual o cenário é construído está especificado na descrição, e a ideia é se colocar no lugar desse usuário, o uso da primeira pessoa pode ser uma forma coerente de escrever.
Quem defende essa posição argumenta que o uso da primeira pessoa faz quem lê o cenário perder a referência do papel ou do usuário de que se está falando. Se eu escrevo em um passo “excluo um artigo do sistema”, quem está fazendo isso? Um administrador, um usuário em particular? Um conjunto de papéis?
De certa forma, o uso da terceira pessoa diminui o risco ou a dificuldade de quem lê fazer suposições erradas sobre quem são as partes interessadas envolvidas.
Também se argumenta que o uso da terceira pessoa apresenta a informação de forma mais formal e objetiva.
Não há uma regra geral sobre o ponto de vista a usar para escrever os cenários.
O importante, como já foi dito, é manter a coerência entre a descrição do cenário e os seus passos (sem alternar pontos de vista), respeitar o critério usado caso estejamos acrescentando cenários a um projeto existente e privilegiar a clareza do que se escreve.
Se em todos os cenários de uma mesma feature algumas pré-condições se cumprem, é muito mais prático usar um Background do que escrever a mesma coisa várias vezes. Ele funciona como uma série de passos que serão executados antes de todos os cenários da feature. Vejamos um exemplo:
Feature: Saque de dinheiro
Background: Given o cartão de crédito está habilitado And o saldo disponível na minha conta é positivo And o caixa eletrônico tem dinheiro suficiente Scenario: …
Recomenda-se que o Background seja o mais curto possível em número de passos, porque, se for muito longo, pode ficar difícil entender os cenários seguintes. É sempre melhor que os cenários sejam o mais autocontidos possível e, se houver um Background, que ele seja o mais curto possível.
O Scenario Outline é um tipo de cenário em que se especificam dados de entrada. Ele é muito prático porque, graças a isso, não é necessário escrever um cenário para cada dado de entrada.
Por exemplo:
Scenario outline: Sacar dinheiro com diferentes senhas de cartão. Given o cartão de crédito está habilitado And o saldo disponível na minha conta é positivo And o caixa eletrônico tem dinheiro suficiente When insiro o cartão no caixa eletrônico
And digito o <pin> do cartão
…
Examples:
| pin |
| 1234 |
| 9876 |
As Doc Strings são úteis para adicionar a um passo cadeias de caracteres longas de forma mais organizada. Para usá-las, é preciso colocar o texto desejado no passo entre três aspas (“””). Por exemplo:
Scenario outline: … Given … When … Then recebo o dinheiro And a mensagem de confirmação é exibida com o texto: “”” Prezado cliente: O seguinte valor foi sacado da sua conta nº <account>: <amount>. Obrigado por usar os nossos serviços. “””
Examples:
| pin | account | amount |
| 1234 | 112235489 | 5000 |
| 9876 | 668972214 | 6000 |
Como você pode ver no exemplo anterior, uma Doc String (que é em si um dado de entrada) pode ser usada em combinação com outros dados de entrada para mostrar dados específicos do cenário que está sendo executado.
As Data Tables, na sua estrutura e utilidade, são muito parecidas com os Scenario Outlines. As duas principais diferenças são:
Exemplo de uso de Data Tables:
Scenario: Sacar dinheiro com diferentes senhas de cartão. Given o cartão de crédito está habilitado And o saldo disponível na minha conta é positivo And o caixa eletrônico tem dinheiro suficiente When insiro o cartão no caixa eletrônico And digito o seguinte <pin> e obtenho o resultado <result>:
| pin | result |
| 1234 | Error |
| 9876 | OK |
No exemplo anterior, adicionamos uma segunda coluna, “result”, para indicar o resultado esperado de acordo com o PIN digitado (“1234” é incorreto e “9876” é correto). Não é necessário usar a Data Table dessa forma, mas ela foi incluída como exemplo de como os dados de entrada podem ser usados em um cenário.
O Cucumber oferece a possibilidade de escrever os cenários em diferentes idiomas, seguindo as mesmas convenções que normalmente usamos em inglês.
Para usar esse recurso, a funcionalidade deve começar com “# language:”, seguido do código do dialeto a ser usado (por exemplo, “# language: es”, para espanhol, ou “# language: pt”, para português).
Na documentação oficial do Cucumber, você encontra todas as informações necessárias para usar esse recurso, incluindo o código de cada dialeto e as palavras que devem ser usadas em cada idioma para substituir as habituais.
Em certas ocasiões, pode acontecer de não querermos executar todos os cenários do nosso teste, mas agrupar certos cenários e executá-los separadamente. O Cucumber oferece uma forma de configurar isso por meio de tags. As tags são anotações que servem para agrupar e organizar cenários e até features, e são escritas com o símbolo @ seguido de um texto significativo, por exemplo:
@gui Feature: … @SmokeTest @wip Scenario: … @RegressionTest Scenario: …
É importante observar que as tags que especificamos nos títulos dos feature files serão herdadas pelos cenários desses arquivos, incluindo os Scenario Outlines.
Se tivermos um Scenario Outline sob uma tag, todos os exemplos de dados do cenário serão executados sob essa tag.
Com as tags atribuídas, há muitas formas de configurá-las na execução, na seção tags de @CucumberOptions. Alguns exemplos:
tags = {“@SmokeTest”} executa todos os cenários sob a tag @SmokeTest
tags = {“@gui”} executa todos os cenários sob a tag @gui; como no exemplo temos uma feature sob essa tag, todos os cenários dessa feature serão executados.
tags = {“@SmokeTest, @wip”} executa todos os cenários que estão sob a tag @SmokeTest ou sob a tag @wip (condição OR).
tags = {“@SmokeTest”, “@RegressionTest”} executa todos os cenários que estão sob as tags @SmokeTest e @RegressionTest (condição AND).
tags = {“~@SmokeTest”} ignora todos os cenários sob a tag @SmokeTest.
tags = {“@RegressionTest, ~@SmokeTest”} executa todos os cenários sob a tag @RegressionTest, mas ignora todos os cenários sob a tag @SmokeTest
tags = {“@gui”, “~@SmokeTest”, “~@RegressionTest”} ignora todos os cenários sob as tags @SmokeTest e @RegressionTest, mas executa todos os que estão sob a tag “@gui”; seguindo o exemplo, é como executar todos os cenários da feature que não estão sob nenhuma outra tag.
Em resumo, as tags não só são úteis para organizar e agrupar os nossos cenários/features (o que contribui muito para a clareza do teste), como também permitem executá-los de forma seletiva, por exemplo, executando os cenários mais rápidos com mais frequência.
O que fizemos até aqui foi especificar os passos dos nossos cenários: descrevemos quais processos o teste vai seguir, mas não definimos como queremos que isso seja feito. Isso passa a ser responsabilidade da implementação das sentenças de Gherkin que escrevemos nos cenários (as step definitions).
As step definitions servem ao Cucumber como uma tradução dos passos que escrevemos em ações a executar para interagir com o sistema.
Embora os exemplos de implementação dos passos que veremos a seguir sejam desenvolvidos em Java, vale mencionar que o Cucumber também pode ser usado com JavaScript, Ruby, C++ e outras linguagens.
Para começar a escrever step definitions, se estivermos trabalhando em uma IDE com as dependências de Gherkin e Cucumber já instaladas, ela vai sugerir que os implementemos (eles aparecem sublinhados) e vai permitir criar um arquivo .java ou escolher um em que já tenhamos passos implementados. Escolher qualquer uma dessas duas opções gera um método na classe; por exemplo, se decidirmos criar uma step definition para o passo:
Given o cartão de crédito está habilitado
Vamos gerar automaticamente um método com uma anotação, em que o texto do cabeçalho corresponde à descrição do passo:
@Given(“^o cartão de crédito está habilitado$”) public void verifyEnabledCard() throws Throwable { // Escreva aqui o código que transforma a frase acima em ações concretas throw new PendingException(); }
Caso o passo inclua dados de entrada definidos por meio de Scenario Outline ou Data Tables, esses dados são incluídos na anotação como expressões regulares e, no método, como parâmetros recebidos:
@When(“^digito o \”([0-9]+)\” do cartão $”) public void enterPIN(int pin) throws Throwable { // Escreva aqui o código que transforma a frase acima em ações concretas throw new PendingException(); }
Ao fazer isso, automaticamente o passo na feature (a sentença em Gherkin) já reconhece onde está a implementação. Alguns pontos importantes ao implementar step definitions: O mais recomendável é criar step definitions que só precisem ser implementadas uma vez e reutilizadas em muitos cenários (até de features diferentes).
Isso é prático não só para economizar a quantidade de código a escrever, mas também contribui muito para a manutenibilidade dos testes, já que, no fim, será menor o número de step definitions que teremos de modificar em qualquer caso.
Uma forma de reutilizar step definitions é defini-las em Scenario Outlines e parametrizá-las.
Deixamos algumas referências caso você queira continuar lendo sobre BDD, boas práticas de Cucumber ou Gherkin:
Notícias, artigos e recursos para construir software melhor.
Leia sobre nossa política de privacidade.
