Conhecendo o CucumberJS

Artigos

Conhecendo o CucumberJS

Fernando Papito
Escrito por Fernando Papito em 15 de julho de 2019
Junte-se a mais de 7000 alunos

Entre para nossa lista e receba conteúdos exclusivos e com prioridade

Neste artigo você vai…

  • Instalar o CucumberJS
  • Escrever seu primeiro cenário com a sintaxe do Gherkin
  • Automatizar o cenário com Javascript e NodeJS
  • Executar especificações vivas com Cucumber
  • Entender o fluxo básico do BDD (Behavior-Driven Development)

Vamos usar o Cucumber e BDD para desenvolver uma pequena biblioteca que possa descobrir qual o prato do dia na capital paulista.

Antes de começarmos, você precisará do NodeJS instalado.
https://nodejs.org/en/

Abra um terminal para verificar se o NodeJS está instalado corretamente:

node -v
npm -v

Crie um projeto do ZERO

mkdir c:\qaninja
mkdir c:\qaninja\cucumberjs
mkdir c:\qaninja\cucumberjs\prato-do-dia
cd c:\qaninja\cucumberjs\prato-do-dia
npm init --yes
npm install cucumber --save-dev

Abra o arquivo package.json e deixe igualzinho o exemplo abaixo:

{
  "name": "prato-do-dia",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "cucumber-js"
  },
  "keywords": ["nodejs", "cucumberjs", "bdd", "qaninja", "javascript"],
  "author": "Fernando Papito",
  "license": "ISC",
  "devDependencies": {
    "cucumber": "^5.1.0"
  }
}

Preparando a estrutura do Cucumber

mkdir features
mkdir features/step_definitions

Na pasta “prato-do-dia”, crie um arquivo com o nome cucumber.js
Deixe conforme o exemplo abaixo:

module.exports = {
  default: `--format-options '{"snippetInterface": "synchronous"}'`
}

Agora crie também o arquivo steps.js dentro da pasta “step_definitions” e cole o seguinte código:

const assert = require('assert');
const { Given, When, Then } = require('cucumber');

Verificando o CucumberJS está funcionando

Execute o comando:

npm test

O Cucumber vai avisar que não encontrou nenhuma especificação para ser executada. Igualmente ao resultado abaixo:

0 scenarios
0 steps
0m00.000s

Especificando cenários para uma estória de usuário

Quando fazemos o BDD (Desenvolvimento Guiado por Comportamento) com o Cucumber, usamos exemplos concretos para especificar o que queremos que o app faça.

Sobre o BDD

Os cenários devem ser criados antes do código do app. Eles começam sua vida como uma especificação executável . À medida que o app vai sendo codificado, os cenários assumem um papel como documentação viva e testes automatizados .

No Cucumber, um exemplo é chamado de cenário . Os cenários são definidos nos arquivos com extensão .feature, e devem estar dentro da pasta features

Estão, vamos fazer o seguinte:
Dentro da pasta features, crie um arquivo com o nome prato_do_dia.feature
Abra o arquivo no seu editor preferido (VSCode é top) e deixe assim:

#language:pt

Funcionalidade: Prato do dia!
  Queremos saber qual o prato do dia na capital paulista

  Cenário: Hoje é dia de virado a paulista
    Dado que hoje é "segunda-feira"
    Quando eu pergunto qual é o prato do dia
    Então a resposta deve ser "Virado a Paulista"

A primeira linha define o idioma da sintaxe do Gheckin.

Na linha 2, temos a palavra-chave Funcionalidade: com o nome da mesma. Por questões de boas práticas, recomendo usar um nome semelhante ao nome do arquivo.

Na linha 4, uma breve descrição do recurso. o Cucumber não executa a descrição, é apenas documentação.

A linha 6 Cenário: Hoje é dia de virado a paulista é um cenário de uso, que descreve o comportamento do usuário ao usar o  app que será desenvolvido.

As últimas três linhas começando com DadoQuandoEntão são os steps para reproduzir o comportamento do cenário. são do nosso cenário. É isso que o Cucumber irá executar para desenvolvermos o app.

Executando cenário indefinido

Agora que temos um cenário bem bonito, vamos pedir ao Cucumber para executá-lo. No terminal digite cucumber conforme abaixo:

npm test

O Cucumber finaliza a execução como undefined. Quer dizer que deu ruim? absolutamente não :). Olha que top, o cucumber percebeu que não existem funções em Javascript que automatizam o comportamento e já está sugerindo as funções (esqueleto) em Javascript para avançamos com o processo de desenvolvimento do app Prato do Dia.

UUU

Warnings:

1) Scenario: Hoje é dia de virado a paulista # features/prato-do-dia.feature:6
   ? Dado que hoje é "segunda-feira"
       Undefined. Implement with the following snippet:

         Given('que hoje é {string}', function (string) {
           // Write code here that turns the phrase above into concrete actions
           return 'pending';
         });
       
   ? Quando eu pergunto qual é o prato do dia
       Undefined. Implement with the following snippet:

         When('eu pergunto qual é o prato do dia', function () {
           // Write code here that turns the phrase above into concrete actions
           return 'pending';
         });
       
   ? Então a resposta deve ser "Virado a Paulista"
       Undefined. Implement with the following snippet:

         Then('a resposta deve ser {string}', function (string) {
           // Write code here that turns the phrase above into concrete actions
           return 'pending';
         });
       

1 scenario (1 undefined)
3 steps (3 undefined)
0m00.000s

No arquivo steps.js em features/step_definitions/, copie as funcções no arquivo steps.js

const assert = require('assert');
const { Given, When, Then } = require('cucumber');

Given('que hoje é {string}', function (string) {
    // Write code here that turns the phrase above into concrete actions
    return 'pending';
});

When('eu pergunto qual é o prato do dia', function () {
    // Write code here that turns the phrase above into concrete actions
    return 'pending';
});

Then('a resposta deve ser {string}', function (string) {
    // Write code here that turns the phrase above into concrete actions
    return 'pending';
});

Executando cenário como pendente

Agora que temos os steps em funções javascript, vamos pedir ao Cucumber para executá-lo novamente. No terminal digite cucumber e veja o resultado conforme o exemplo abaixo:

P--

Warnings:

1) Scenario: Hoje é dia de virado a paulista # features/prato-do-dia.feature:6
   ? Dado que hoje é "segunda-feira" # features/step_definitions/steps.js:4
       Pending
   - Quando eu pergunto qual é o prato do dia # features/step_definitions/steps.js:9
   - Então a resposta deve ser "Virado a Paulista" # features/step_definitions/steps.js:14

1 scenario (1 pending)
3 steps (1 pending, 2 skipped)
0m00.000s

O Cucumber encontrou os códigos Javascript que dão vida a especificação, mas o resultado ficou como pendente , ou seja, ja temos a estrutura que testa e agora falta implementar. Olha o TDD na prática.

Executando cenário com falha

Quando fazemos o BDD

(Desenvolvimento Orientado por Comportamento) com o Cucumber, usamos exemplos concretos para especificar o que queremos que o software faça. Os cenários são gravados antes do código do app. Eles começam sua vida como uma especificação executável . À medida que o produto surge, os cenários assumem um papel como documentação viva e testes automatizados .

Altere os steps, conforme o exemplo abaixo:

const assert = require('assert');
const { Given, When, Then } = require('cucumber');

function pratoDoDia(dia) {
}

Given('que hoje é {string}', function (dia) {
    this.hoje = dia;
});

When('eu pergunto qual é o prato do dia', function () {
    this.valorObtido = pratoDoDia(this.hoje);
});

Then('a resposta deve ser {string}', function (valorEsperado) {
    assert.equal(this.valorObtido, valorEsperado);
});

Perceba que eu fiz a implementação do comportamento, onde a função pratoDoDia representa a unidade de código que deve ser desenvolvida. Seguida pelos steps que ativam e acessam os recursos para que a mesma seja testada.

Então execute o Cucumber novamente.

As coisas estão ficando muito chiques! Os dois primeiros passos estão passando, mas o último está falhando.

Isso acontece porque o método “prado_do_dia” só recebe o valor “segunda-feira”, mas não possui uma regra para tratar essa informação e fazer com que o comportamento especificado devolva o valor esperado para o cenário. Revolva isso conforme o exemplo abaixo:

function pratoDoDia(dia) {
    if (dia === 'segunda-feira') {
        return 'Virado a Paulista'
    }
}

Agora veja cenário passando

Execute o Cucumber novamente:

...

1 scenario (1 passed)
3 steps (3 passed)
0m00.002s

Adicionando mais um cenário

Vamos adicionar mais um cenário, onde o valor de entrada será “terça-feira” e valor esperado (saída) será “Dobradinha”.

#language:pt

Funcionalidade: Prato do dia!
  Queremos saber qual o prato do dia na capital paulista

  Cenário: Hoje é dia de virado a paulista
    Dado que hoje é "segunda-feira"
    Quando eu pergunto qual é o prato do dia
    Então a resposta deve ser "Virado a Paulista"

  Cenário: Hoje é dia de dobradinha
    Dado que hoje é "terça-feira"
    Quando eu pergunto qual é o prato do dia
    Então a resposta deve ser "Dobradinha"

Execute o cucumber de novo:

O segundo falhou. Isso ocorre porque ainda não implementamos a regra de negócio para terça-feira!

Vamos trocar o if pelo case e deixar assim:

function pratoDoDia(dia) {
    switch (dia) {
        case 'segunda-feira':
            return 'Virado a Paulista'
        case "terça-feira":
            return "Dobradinha"
    }
}

Execute o cucumber mais uma vez:

......

2 scenarios (2 passed)
6 steps (6 passed)
0m00.002s

Usando cenários múltiplos

Sabemos que há mais dias na semana do que apenas segunda e terça-feira. E nestes dias também temos pratos típicos da capital paulista. Portanto vamos atualizar nosso cenário para usar variáveis ​​e avaliar mais possibilidades. 

Esta técnica é chamada de Scenario Outline. Em português, Delineação do Cenário ou Esquema do Cenário.

Digite o comando: ./node_modules/.bin/cucumber-js –i18n-keywords pt no terminal

Voce verá todas as palavras reservadas em português.

Atualize o prato_do_dia.feature, conforme o exemplo abaixo:

#language:pt

Funcionalidade: Prato do dia!
  Queremos saber qual o prato do dia na capital paulista

  Esquema do Cenário: Descubra o prato do dia

      Dado que hoje é "<dia>"
      Quando eu pergunto qual é o prato do dia
      Então a resposta deve ser "<resposta>"

        Exemplos:
            | dia           | resposta          |
            | segunda-feira | Virado a Paulista |
            | terça-feira   | Dobradinha        |
            | quarta-feira  | Feijoada          |
            | quinta-feira  | Macarrão          |
            | sexta-feira   | Filé de Peixe     |

Execute o cucumber mais uma vez:

Resultado de imagem para TDD everywhere

Implementando os demais cenários

Agora que temos todos os cenários, devemos fazer algumas refatorações:

function pratoDoDia(dia) {
    switch (dia) {
        case 'segunda-feira':
            return 'Virado a Paulista'
        case "terça-feira":
            return "Dobradinha"
        case "quarta-feira":
            return "Feijoada"
        case "quinta-feira":
            return "Macarrão"
        case "sexta-feira":
            return "Filé de Peixe"
    }
}

Executando o Cucumber mais uma vez:

...............

5 scenarios (5 passed)
15 steps (15 passed)
0m00.001s

Finalizando

Neste breve artigo, você viu como instalar o CucumberJS, e como seguir o processo do BDD para desenvolver uma funcionalidade simples guiado pelo comportamento!

Você pode conferir o projeto final no meu Github

https://github.com/papitoio/prato-do-dia-js

Quer saber mais sobre CucumberJS e BDD? Veja nossos cursos!

E ai,

o que você achou deste conteúdo? Conte nos comentários.

Entre para nossa lista e receba conteúdos exclusivos e com prioridade

Junte-se a mais de 7000 alunos