Category Archives: Teste Automatizado

Cucumber – Exemplo prático de Calculadora

Introdução

Este post tem o objetivo de demonstrar, de forma prática, a metodologia do uso do Cucumber, usando Eclipe e Java.

Aprenda mais sobre o Cucumber aqui.

Criação do Projeto

Vamos criar um projeto Maven Java no Eclipse.

  1. Abra o Eclipse.
  2. Clique no menu File / New / Maven Project
  3. Deixe os valores padrão e clique em Next
  4. Utilize o archetype quickstart (padrão) e clique em Next
  5. Configure os parâmetros do projeto
    1. Group Id: com.maxidica.tdd
    2. Artifact Id: calculadora
    3. Deixe os demais campos padrão
    4. Clique no botão Finish

Ajustando pom.xml

Agora vamos incluir as dependências necessárias para o projeto.

  1. Abra o arquivo pom.xml
  2. Clique na aba Dependencies
  3. Remova o junit 3.8.1
  4. Adicione o junit 4 (4.1.2)
  5. Adicione as dependências do Cucumber
    1. cucumber-java
    2. cucumber-junit
    3. cucumber-picocontainer
    4. Configure as dependências com escopo test

Criando arquivo de estórias

Iremos criar o diretório de fonte, chamado resource.

  1. Clique com o botão direito no projeto
  2. Escolha New / Source Folder
  3. Digite src/test/resource
  4. Clique em Finish

Eliminando classes desnecessárias

Exclua todos os arquivos .java do projeto (App.java e AppTest.java).

Criando a classe CalcRunner

Essa classe é responsável pela execução do teste.

  1. Clique com o botão direito em src/test/java
  2. Escolha New / Class
  3. Digite CalcRunner
  4. Clique em Finish

package com.maxidica.tdd.calculadora;

import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(
plugin = {“html:target/cucumber-html-report”, “json:target/cucumber-json-report.json”},
features = “src/test/resource”
)
public class CalcRunner {

}

Criando arquivo feature

Esse arquivo é responsável pela execução dos testes.

  1. Clique com o botão direito em src/test/resource
  2. Escolha New / File
  3. Digite o nome Calc.feature
  4. Digite o conteúdo abaixo
#language: en
Feature: Calc
   Como usuario entrar com 2 valores
   Com objetivo de obter um resultado

   Scenario: Somar
   Given que eu escolha somar
   When eu preencho o primeiro número com o valor '1'
   And eu preencho o segundo número com o valor '1'
   Then eu devo ver o resultado como '2'

 

Rodando o 1º teste

Esse teste criará a estrutura para definirmos a classe de execução.

  1. Clique com o botão direito na classe CalcRunner.java
  2. Escolha Run As / JUnit Test
  3. Na aba Console, aparecerá o resultado com os métodos a serem codificados
1 Scenarios (1 undefined)
4 Steps (4 undefined)
0m0,000s


You can implement missing steps with the snippets below:

@Given("^que eu escolha somar$")
public void que_eu_escolha_somar() throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

@When("^eu preencho o primeiro número com o valor '(\\d+)'$")
public void eu_preencho_o_primeiro_número_com_o_valor(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

@When("^eu preencho o segundo número com o valor '(\\d+)'$")
public void eu_preencho_o_segundo_número_com_o_valor(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

@Then("^eu devo ver o resultado como '(\\d+)'$")
public void eu_devo_ver_o_resultado_como(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

Criar classe com os passos do teste

Agora, iremos criar a classe responsável pela execução dos passos do teste.

  1. Clicar com o botão direito em src/test/java
  2. Escolher New / Class
  3. Defina o nome como CalcSteps
  4. Então, basta copiar os métodos (apresentados no Console) para dentro da classe
package com.maxidica.tdd.calculadora;

import cucumber.api.PendingException;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class CalcSteps {

@Given("^que eu escolha somar$")
public void que_eu_escolha_somar() throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

@When("^eu preencho o primeiro número com o valor '(\\d+)'$")
public void eu_preencho_o_primeiro_número_com_o_valor(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

@When("^eu preencho o segundo número com o valor '(\\d+)'$")
public void eu_preencho_o_segundo_número_com_o_valor(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

@Then("^eu devo ver o resultado como '(\\d+)'$")
public void eu_devo_ver_o_resultado_como(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

}

Criar a aplicação

Essa classe é que conterá as regras de negócio que queremos, neste caso, calcular a soma de números.

  1. Clique com o botão direito em src/main/java
  2. Escolha New / Class
  3. Defina o nome Calc
package com.maxidica.tdd.calculadora;

public class Calc {

public int somar( int a, int b ) {
return a + b;
}

}

Codificando os métodos na classe CalcSteps

Agora, precisamos codificar os métodos.

package com.maxidica.tdd.calculadora;

import static org.junit.Assert.assertEquals;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class CalcSteps {

Calc calc;
int num1, num2;

@Given("^que eu escolha somar$")
public void que_eu_escolha_somar() {
calc = new Calc();
}

@When("^eu preencho o primeiro número com o valor '(\\d+)'$")
public void eu_preencho_o_primeiro_número_com_o_valor(int arg1) {
num1 = arg1;
}

@When("^eu preencho o segundo número com o valor '(\\d+)'$")
public void eu_preencho_o_segundo_número_com_o_valor(int arg1) {
num2 = arg1;
}

@Then("^eu devo ver o resultado como '(\\d+)'$")
public void eu_devo_ver_o_resultado_como(int arg1) {
assertEquals(arg1,calc.somar(num1,num2));
}

}

Teste final

Então podemos executar o teste final na classe CalcRunner.

  1. Clique com o botão direito na classe CalcRunner.java
  2. Escolha Run As / JUnit Test
  3. Verifique o resultado no Console
1 Scenarios (1 passed)
4 Steps (4 passed)
0m0,146s

Provocando erro no teste

Para executar a falha, devemos alterar o arquivo feature.

  1. Edite o arquivo Calc.feature
  2. Altere o texto, eu devo ver o resultado como ‘3’
  3. Salve o arquivo
  4. Rode o teste na classe CalcRunner.java
  5. Perceba que no Console, apresentará erro de execução
1 Scenarios (1 failed)
4 Steps (1 failed, 3 passed)
0m0,163s

java.lang.AssertionError: expected:<3> but was:<2>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:645)
at org.junit.Assert.assertEquals(Assert.java:631)
at com.maxidica.tdd.calculadora.CalcSteps.eu_devo_ver_o_resultado_como(CalcSteps.java:31)
at ✽.Then eu devo ver o resultado como '3'(Calc.feature:10)

Essa é a parte interessante do teste. Alterando o arquivo feature, podemos validar se a aplicação está funcionando de forma correta.

Você pode baixar o projeto pronto no Github.

 

Cucumber – Linguagem Gherkin

Cucumber é uma ferramenta que suporta Behavior Driven Development (BDD), traduzindo ao pé da letra significa: “desenvolvimento orientado por comportamento”, simples assim,ou seja, BDD nada mais é do que descrever os COMPORTAMENTOS de um sistema utilizando linguagem Gherkin.

O que é Gherkin ?

Gherkin é uma linguagem natural que tanto o cucumber quanto todos os interessados(usuários, desenvolvedores, testadores, etc…) entendem, dessa forma, todas as necessidades reais do usuário e projeto são descritas, gerando uma documentação viva e valor pro negócio.

Não altere a estrutura padrão

Como já sabemos, o cucumber utiliza linguagem gherkin, que é uma linguagem natural e de fácil entendimento, porém possui algumas palavras “chaves” e são elas:

Dado (Given)
O “Dado” seria básicamente as pré-condições do cenário.

Quando (When)
O “Quando” serve descrever as ações chave que o usuário executa, resumidamente seria qualquer ação de interação do usuário com o sistema.

Então (Then)
O “Então” visa mostrar as saídas, os resultados das ações executadas, seriam basicamente os resultados esperados.

Exemplo:

Dado número A
Quando somar A+B
Então resultado deve ser C

Portanto mantenha sempre esse padrão: Dado, Quando, EntãoNÃO altere isso e NÃO repita essas palavras no mesmo cenário, para não repetir essas palavras, caímos no segundo tópico das melhores práticas.

Faça uso do “E” e “Mas”

E (And)
O “E” visa complementar qualquer uma das palavras chaves citadas anteriormente, por exemplo:

Dado número A
número B
Quando somar A+B
dividir por C
Então resultado deve ser D

Mas (But)

O “Mas” seria a forma negativa do “Então”, basicamente, quando o resultado esperado for que o usuário NÃO DEVE receber.

Dado número A
E número B
Quando somar A+B
E dividir por C
Então resultado deve ser exibido
Mas não deve ser igual a D

Use “Contexto” e ganhe tempo

Uma regra básica que serve para a vida, se você está fazendo o mesmo trabalho duas vezes, de duas uma, ou você não fez direito, ou algo de errado não está certo.

No cucumber é para isso que existe o contexto(background), para remover aquilo que está sendo repetido em todos os cenários e centralizar em um único lugar, no caso o contexto. Vamos dar um exemplo para ficar bem mais fácil e compreensível.

Reparem que no exemplo acima, a seguinte linha está sendo repetida em todos os cenários:

Dado que eu esteja logado

Vamos ao “Contexto”

Viu como diminuímos o retrabalho? Mais fácil do que fazer regime!

“Contexto” é bom quando usado para coisas simples, não é recomendável utilizar para cenários mais complexos complexas.

“Contexto” é executado antes de cada um dos cenários, mas após qualquer um dos Hooks.

Use tags

#VemNeMimSextaFeira, é praticamente a mesma coisa, só que no lugar da hashtag, utiliza o @. Com isso você consegue filtrar e executar cenários específicos, por exemplo:

@validar_login @crítico @wip @cadastrar_cliente

Pode utilizar mais de uma tag por funcionalidade

Seja mais comportamental do que procedural

Não escreva todos os passo a passo de cada cenário, basta descrever o comportamento. exemplo:

Dado que o usuário esteja na tela de login
Quando preencher o campo usuário
E preencher o campo senha
E clicar no botão entrar
Então o sistema deve logar
e exibir dashboard

Pode isso Arnaldo ? Poder pode, mas não é recomendável, o mais correto seria:

Dado que o usuário esteja na tela de login
Quando informar os dados válidos
Então o sistema realizar o login
E o sistema exibir mensagem de “Bem Vindo”

Sempre descreva na terceira pessoa

Pare de utilizar “eu” nas descrições dos cenários, procure utilizar sempre na terceira pessoa. Reparem no cenário abaixo:

Dado que eu esteja…

Quando eu adiciono…

Não, não é assim! utilize na terceira pessoa.

Dado que o usuário ou o cliente esteja logado

Quando usuário ou cliente adicionar um produto no carrinho

Melhorou ?

Utilize Scenario Outline

Quando os cenários têm validações resultados parecidos, podemos utilizar os Scenarios Outline, ou Esquemas de cenário. Vamos ao exemplo:

Cenário: mostrar o resultado quando executar uma operação de adição
Dado que o usuário esteja na calculadora
Quando pressionar o número 4
pressionar o número 2
escolher adição
Então o sistema devera mostrar o resultado igual à 6

Cenário: mostrar o resultado quando executar uma operação de subtração
Dado que o usuário esteja na calculadora
Quando pressionar o número 4
pressionar o número 2
escolher subtração
Então o sistema devera mostrar o resultado igual à 2

Cenário: mostrar o resultado quando executar uma operação de multiplicação
Dado que o usuário esteja na calculadora
Quando pressionar o número 4
pressionar o número 2
escolher multiplicação
Então o sistema devera mostrar o resultado igual à 8

Repare que são praticamente as mesmas validações, para facilitar tanto na implementação e na manutenção, existe no cucumber os scenarios outline. E ficaria da seguinte maneira:

Cenário: mostrar o resultado quando executar uma operação na calculadora
 Dado que o usuário esteja na calculadora
 Quando pressionar o <número1>
 E pressionar o <número2>
 E escolher a <operação>
 Então o sistema devera mostrar o <resultado>
Exemplo:
    | numero1    | numbero2   |    operação    | resultado|
    |     4      |      2     |      soma      |   6      |
    |     4      |      2     |   subtração    |   2      |
    |     4      |      2     | multiplicação  |   8      |
    |     4      |      2     |     divisão    |   2      |

A primeira linha da tabela representa as variáveis escritas assim <variável> nos cenários e as outras linhas são os exemplos para execução dos testes com seus respectivos resultados esperados.

Viu como fica mais fácil de escrever e manter os cenários? Além de serem mais legíveis também.

Organize Diretórios

Existem outras formas de organizar os diretórios dentro do projeto. Porém uma boa prática é criar uma pasta Features e dentro dela criar as seguintes subpastas: pages, onde vão ficar todos os objetos de cada pagina(não precisa se preocupar com isso agora), specifications, onde vão ficar todos os comportamentos do sistema escrito em cucumber, step_definitions, onde vão ficar todos os passo a passo gerados a partir das nossa especificações e support, onde vão ficar algumas configurações, conforme exemplo abaixo: