Fork us

Escrevendo Features

Behat é uma ferramenta para testar o o comportamento de sua aplicação, utilizando uma linguagem especial chamada Gherkin. Gherkin é uma Business Readable, Domain Specific Language criada especificamente para a descrição de comportamentos. Isto lhe dá a habilidade de remover detalhes lógicos dos testes de comportamento.

O Gherkin serve como documentação do seu projeto, bem como para testes automatizados. O Behat também tem uma característica bônus: Ele fala para você usando linguagem verdadeira, humana lhe dizendo o código que você deve escrever.

Dica:

Se você ainda é novo no Behat, vá para Construindo Modelo de Domínio primeiro e então retorne aqui para aprender mais sobre Gherkin.

Sintaxe Gherkin

Bem como YAML e Python, Gherkin é uma linguagem orientada a espaços, ela usa indentação para definir a estrutura. Os fins de linha encerram as declarações (denominados etapas) e espaços ou tabs também podem ser usados para indentação (nós sugerimos a você usar espaços para melhor portabilidade). Finalmente, a maioria das linhas em Gherkin iniciam com uma palavra chave especial:

# language: pt
Funcionalidade: Algum texto descritivo conciso do que é desejado
  A fim de realizar um valor de negócio
  Como ator explicito do sistema
  Eu quero ganhar algum resultado benéfico que promova a meta

 Texto adicional...

  Cenário: Uma determinada situação de negócios
    Dado uma pré condição
    E uma outra pré condição
    Quando uma ação é feita pelo ator
    E uma outra ação
    E outra ação diferente
    Então um resultado testável é alcançado
    E outra coisa que possamos verificar também acontece

  Cenário: Uma situação diferente
    ...

O analisador divide a entrada em funcionalidades, cenários e etapas. Vamos analisar o exemplo:

.# Funcionalidade: Algum texto descritivo conciso do que é desejado
inicia a feature e lhe dá um título. Aprenda mais sobre Funcionalidades na seção “`Features`_”.
.# As próximas três linhas (A fim de ..., Como um ..., Eu quero...)
dão um contexto para as pessoas que leem a sua funcionalidade e descreve o valor do negócio derivada da inclusão da funcionalidade em seu software. Estas linhas não são analisadas pelo Behat e não requerem uma estrutura.
.# Cenário: Uma determinada situação de negócios inicia o cenário e
contêm uma descrição do cenário. Aprenda mais sobre cenários na seção “`Scenarios`_
.# As próximas 7 linhas são etapas do cenário, cada uma das quais é comparada
com um padrão definido em outro lugar. Aprenda mais sobre etapas na seção “`Steps`_

.# Cenário: Uma situação diferente inicia o próximo cenário e assim por diante.

Quando você está executando a funcionalidade, a porção da direita de cada etapa (após as palavras chaves como Dado, E, Quando, etc) coincide com um padrão, que executa uma função callback do PHP. Você pode ler mais sobre etapas de coincidências e execução em Definindo Ações Reutilizáveis.

Funcionalidades

Todos arquivos *.feature convencionalmente consistem em uma funcionalidade única. Linhas iniciando com a palavra chave Funcionalidade: seguido de três linhas identadas iniciam uma funcionalidade. Usualmente uma Funcionalidade contém uma lista de Cenários. Você pode escrever qualquer coisa que você precise até o primeiro cenário, que inicia com Cenário: (ou o seu equivalente) em uma nova linha. Você pode usar tags para agrupar Funcionalidades e Cenários, independente da estrutura do seu arquivo e diretório.

Todos cenários consistem em uma lista de etapas, que devem iniciar com uma das palavras chaves Dado, Quando, Então, Mas ou E. O Behat trata eles do mesmo modo, mas você não deve fazer isto. Aqui temos um exemplo:

# language: pt
Funcionalidade: Servir café
    A fim de ganhar dinheiro
    Os clientes devem ser capazes de
    comprar café a todo momento

  Cenário: Compra último café
    Dado que tenha 1 café sobrando na máquina
    E eu tenha depositado 1 real
    Quando eu pressionar o botão de café
    Então eu deveria ser servido de um café

Além do básico Cenário, uma funcionalidade pode conter Esquema do Cenário e Contexto.

Cenário

Cenários são uma das principais estruturas do Gherkin. Todo cenário deve iniciar com a palavra chave Cenário: , opcionalmente seguido de um título de cenário. Cada funcionalidade pode ter um ou mais cenários e todo cenário consiste em uma ou mais `etapa`_.

Os cenários seguintes tem cada um 3 etapas:

Cenário: Wilson posta em seu blog
  Dado que eu estou logado como Wilson
  Quando eu tento postar "A terapia cara"
  Então eu devo ver "Seu artigo foi publicado."

Cenário: Wilson falha ao postar algo no blog de outra pessoa
  Dado que eu estou logado como Wilson
  Quando eu tento postar "Greg esbraveja contra impostos"
  Então eu devo ver "Hey! Este não é o seu blog!"

Cenário: Greg posta em blog cliente
  Dado que eu estou logado como Greg
  Quando eu tento postar "Terapia Cara"
  Então eu devo ver "Seu artigo foi publicado."

Esquema do Cenário

Copiar e colar cenários para usar diferentes valores pode ser muito tedioso e repetitivo:

Cenário: Comer 5 em cada 12
  Dado que tenho 12 pepinos
  Quando eu comer 5 pepinos
  Então eu devo ter 7 pepinos

Cenário: Comer 5 em cada 20
  Dado que tenho 20 pepinos
  Quando eu comer 5 pepinos
  Então eu devo ter 15 pepinos

Os Esquemas do Cenários nos permitem formular estes exemplos com maior precisão através da utilização de um modelo com espaços reservados:

Esquema do Cenário: Comendo
  Dado que tenho <antes> pepinos
  Quando eu comer <come> pepinos
  Então eu devo ter <depois> pepinos

  Exemplos:
    | antes | come | depois |
    |  12   |  5   |   7    |
    |  20   |  5   |   15   |

As etapas do Esquema do Cenário fornecem um modelo que nunca é executado diretamente. Um Esquema do Cenário é executado uma vez para cada linha na seção de exemplos abaixo dela (exceto para a primeira linha que é o cabeçalho).

O Esquema do Cenário utiliza espaços reservados, que estão contidos < > nas etapas de saída do Cenário. Por exemplo:

Dado <Eu sou um espaço reservado e estou ok>

Pense em um espaço reservado como uma variável. Isto pode ser substituído por um valor real das linhas da tabela de Exemplos:, onde o texto entre os < > de espaço reservado corresponde ao cabeçalho da coluna da tabela. O valor substituído pelo espaço reservado muda a cada execução subsequente do Esquema do Cenário, até que o fim da tabela de Exemplos seja alcançado.

Tip

Você também pode usar os espaços reservados em Argumentos Multilineos.

Note

Sua etapa de definições nunca terá que coincidir com o próprio texto do espaço reservado, mas sim os valores terão que substituir o espaço reservado.

Então quando executamos a primeira linha do nosso exemplo:

Esquema do Cenário: Comer
  Dado que temos <antes> pepinos
  Quando eu comer <come> pepino
  Então teremos <depois> pepinos

  Exemplos:
    | antes | come | depois |
    |  12   |   5  |   7    |

O cenário que realmente é executado é:

Cenário: Comer
  # <antes> é substituído por 12:
  Dado que temos 12 pepinos
  # <come> é substituído por 5:
  Quando eu comer 5 pepino
  # <depois> é substituído por 7:
  Então teremos 7 pepinos

Contexto

Contexto permite a você adicionar algum contexto a todos os cenários em um único recurso. Um Contexto é como um Cenário sem título, que contém uma série de etapas. A diferença ocorre quando ele é executado: o contexto será executado antes de cada um de seus cenários, mas depois dos seus hooks BeforeScenario (Hooking no Processo de Teste).

# language: pt
Funcionalidade: Suporte a múltiplos sites

Contexto:
    Dado um administrador global chamado "Greg"
    E um blog chamado "Greg esbraveja contra impostos"
    E um cliente chamado "Wilson"
    E um blog chamado "Terapia Cara" de propriedade de "Wilson"

Cenário: Wilson posta em seu próprio blog
    Dado que eu esteja logado como Wilson
    Quando eu tentar postar em "Terapia Cara"
    Então eu devo ver "Seu artigo foi publicado."

Cenário: Greg posta no blog de um cliente
    Dado que eu esteja logado como Greg
    Quando eu tentar postar em "Terapia Cara"
    Então eu devo ver "Seu artigo foi publicado"

Etapas

Funcionalidades consistem em etapas, também conhecidas como Dado, Quando e Então.

O Behat não faz distinção técnica entre estes três tipos de etapas, contudo, nós recomendamos fortemente que você faça! Estas palavras foram cuidadosamente selecionadas para o seu propósito e você deve saber que o objetivo é entrar na mentalidade BDD.

Robert C. Martin escreveu um ótimo post sobre o conceito de BDD Dado-Quando-Então onde ele pensa neles como uma máquina de estados finitos.

Dado

O propósito da etapa Dado é colocar o sistema em um estado conhecido antes do usuário (ou sistema externo) iniciar a interação com o sistema (na etapa Quando). Evite falar sobre a interação em Dado. Se você trabalhou com casos de uso, Dado é a sua pré condição.

Tip

Tudo bem chamar a camada de “dentro” da camada de interface do usuário aqui (no Symfony: falar com os modelos).

Quando

O propósito da etapa Quando é descrever a ação chave que o usuário executa (ou, usando a metáfora de Robert C. Martin, a transição de estado).

Então

O propósito da etapa Então é observar saídas. As observações devem estar relacionadas com o valor/benefício de negócios na sua descrição da funcionalidade. As observações devem inspecionar a saída do sistema (um relatório, interface de usuário, mensagem, saída de comando) e não alguma coisa profundamente enterrado dentro dela (que não tem valor de negócios e ao invés disso faz parte da implementação).

Caution

Embora possa ser tentador implementar etapas Então para apenas olhar no banco de dados - resista à tentação. Você deve verificar somente saídas que podem ser observadas pelo usuário (ou sistema externo). Se a base de dados somente é visível internamente por sua aplicação, mas é finalmente exposta pela saída do seu sistema em um navegador web, na linha de comando ou uma mensagem de email.

E, Mas

Se você tem várias etapas Dado, Quando ou Então você pode escrever:

Cenário: Múltiplos Dado
  Dado uma coisa
  Dado outra coisa
  Dado mais outra coisa
  Quando eu abrir meus olhos
  Então eu verei qualquer coisa
  Então eu não verei qualquer outra coisa

Ou você pode usar etapas E ou Mas, permitindo uma leitura mais fluente do seu Cenário:

Cenário: Múltiplos Dado
  Dado uma coisa
  E outra coisa
  E mais outra coisa
  Quando eu abrir meus olhos
  Então eu verei qualquer coisa
  Mas eu não verei qualquer outra coisa

O Behat interpreta as etapas iniciando com E ou Mas exatamente como as outras etapas, não faz distinção entre elas - Mas você deve!

Argumentos Multilineos

A linha única etapas permite ao Behat extrair pequenas strings de suas etapas e recebê-los em suas definições de etapas. No entanto, há momentos em que você quer passar uma estrutura de dados mais rica a uma definição de etapa.

Para isto foram projetados os Argumentos Multilineos. Eles são escritos nas linhas que seguem imediatamente uma etapa e são passadas para o método definição de etapa como um último argumento.

Etapas de Argumentos Multilineos vem em dois modos: tabelas ou pystrings.

Tabelas

As tabelas são etapas de argumentos úteis para a especificação de um grande conjunto de dados - normalmente como entrada para uma saída de Dado ou como espera de um Então.

Cenário:
  Dado que as seguintes pessoas existem:
    | nome  | email           | fone  |
    | Aslak | aslak@email.com | 123   |
    | Joe   | joe@email.com   | 234   |
    | Bryan | bryan@email.org | 456   |

Attention

Não confunda tabelas com `Esquemas do cenário`_ - sintaticamente eles são idênticos, mas eles tem propósitos diferentes. Esquemas declaram diferentes valores múltiplos ao mesmo cenário, enquanto tabelas são usadas para esperar um conjunto de dados.

PyStrings

Strings multilineas (também conhecidas como PyStrings) são úteis para a especificação de um grande pedaço de texto. O texto deve ser fechado por delimitadores que consistem em três marcas de aspas duplas (`` “”” ``), colocadas em linha:

Cenário:
  Dado uma postagem em um blog chamado "Random" com:
    """
    Algum título, Eh?
    =================
    Aqui está o primeiro parágrafo do meu post.
    Lorem ipsum dolor sit amet, consectetur adipiscing
    elit.
    """

Note

A inspiração para o PyString vem do Python onde """ é usado para delimitar docstrings, mais ou menos como /** ... */ é usado para docblocks em PHP.

Note

A indentação para abrir """ não é importante, apesar de ser uma prática comum deixar dois espaços da etapa de fechamento. A identação dentro das aspas triplas, entretanto, é significante. Cada linha da string passa pela chamada da definição de etapa e será re-indentada de acordo com a abertura """. A indentação além da coluna de abertura """ por conseguinte, será preservada.

Tags

Tags são uma ótima forma de organizar suas funcionalidades e cenários. Considere este exemplo:

@faturamento
Feature: Verifica o faturamento

  @importante
  Cenário: Falta da descrição do produto

  Cenário: Vários produtos

Um Cenário ou Funcionalidade pode ter quantas tags você quiser, basta apenas separá-los com espaços:

@faturamento @brigar @incomodar
Funcionalidade: Verificar o faturamento

Note

Se uma tag existe em uma Funcionalidade, o Behat irá atribuir essa tag para todos os Cenários filhos e Esquemas do Cenário também.

Gherkin em Muitas Línguas

O Gherkin está disponível em muitas linguagens, permitindo você escrever histórias usando as palavras chave de sua linguagem. Em outras palavras, se você fala Francês, você pode usar a palavra Fonctionnalité ao invés de Funcionalidade.

Para checar se o Behat e o Gherkin suportam a sua língua (Francês, por exemplo), execute:

behat --story-syntax --lang=fr

Note

Guarde em sua mente que qualquer linguagem diferente de en precisa ser explicitada com um comentário #language: ... no início de seu arquivo *.feature:

# language: fr
Fonctionnalité: ...ta
  ...

Desta forma, suas funcionalidades realizarão todas as informações sobre o seu tipo de conteúdo, o que é muito importante para metodologias como BDD e também dá ao Behat a capacidade de ter recursos de vários idiomas em uma suíte.