Cucumber: Automação de Testes em Behavior-Driven Development (BDD) editar

Se você já trabalhou em projetos grandes e complexos que envolvem pessoas de diferentes áreas, você sabe os desafios que envolvem explicar os requisitos técnicos para membros da equipe que não são muito familiarizados com ambiente tech.  Nesse contexto, uma ótima ferramenta para resolver esse problema é o Cucumber: ferramenta de automação de testes que entrega uma solução a esses dilemas através da abordagem conhecida como Desenvolvimento Orientado por Comportamento (BDD - Behavior Driven Development).

Mas o que é o Behavior-Driven Development (BDD)? editar

Behavior-Driven Development (BDD), ou Desenvolvimento Orientado por Comportamento, é uma metodologia ágil de desenvolvimento de software que visa aprimorar a comunicação entre os desenvolvedores, setores de qualidade e pessoas não-técnicas ou de negócios em projetos de software. O principal objetivo do BDD é estabelecer uma linguagem comum e clara para descrever os requisitos do sistema, facilitando a compreensão de todos os envolvidos no projeto. Entre as práticas do BDD estão o uso de exemplos para descrever o comportamento de uma aplicação e a automatização de testes baseados nesses exemplos.

O que é Cucumber e como ele usa o BDD? editar

O Cucumber é uma ferramenta open source utilizada para automação de testes de software que suporta BDD, permitindo descrever e detalhar as necessidades dos usuários de modo que todos os membros, técnicos e não técnicos, entendam por completo o fluxo de testes. Assim ele facilita o feedback de diferentes pessoas o que permite aumentar a assertividade da entrega, além de que essa abordagem colaborativa melhora a comunicação do time.

Portanto essa é uma ferramenta bastante útil já que permite alinhar os requisitos do sistema entre as diferentes partes envolvidas no ciclo de desenvolvimento de software, além de validar o funcionamento do sistema em si.

Como o Cucumber funciona? editar

A mágica por trás do Cucumber está associada com a transformação de uma especificação escrita em Gherkin, que segue um conjunto de regras de sintaxe, em código de teste. Gherkin é uma linguagem que permite descrever o comportamento do software sem precisar detalhar como esse comportamento é implementado. As especificações do Gherkin são escritas em cenários dentro dos arquivos de features, que descrevem uma funcionalidade do software e os critérios de aceitação para essa funcionalidade.

O Cucumber lê esses cenários com as especificações e os executa como testes, utilizando steps definitions (definições de passos) escritas em Ruby, Java, ou outra linguagem suportada pelo Cucumber, para simular as ações do usuário e verificar se o comportamento do software está de acordo com o esperado. No gherkin cada exemplo é chamado de scenario. Normalmente, cada scenario possui um conjunto de asserções iniciais sobre o estado do software, um conjunto de passos que descrevem como o usuário interage com o software e um conjunto de asserções finais que descrevem o estado do software após a interação com o usuário.

Exemplo na prática: Testando uma Aplicação de Gerenciamento de Tarefas com Cucumber editar

Suponha que você está criando uma página de login para o seu site. Um teste utilizando cucumber poderia ser estruturado da seguinte forma:

Scenario: O usuário loga com sucesso

Given nenhum usuário logado

When usuário coloca “Lais” na caixa de nome de usuário

And usuário coloca “baiaode2” na caixa de senha

And usuário clica em login

Then usuário “Lais” deveria estar logado

Cada etapa do teste é definida como um step do teste e cada um deve estar associado a alguma função a ser executada. A forma como uma função é atrelada a um passo varia de linguagem para linguagem.

Para ilustrar todo o processo de automação de testes, vamos considerar o desenvolvimento de uma aplicação de gerenciamento de tarefas. Mas antes dos testes em si, é necessário configurar o ambiente. Utilizando o Kotlin como linguagem de programação, o primeiro passo é importar o cucumber. Se você está usando gradle, é preciso adicionar essas dependências no seu arquivo build gradle:

dependencies {

  testImplementation "io.cucumber:cucumber-java8:7.16.1"

  testImplementation "io.cucumber:cucumber-junit:7.16.1"

  testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'

}

Depois do ambiente configurado, vamos implementar aplicação de gerenciamento de tarefas, com as funcionalidades para adicionar, buscar, remover e listar tarefas. Vamos usar o cucumber para testar a classe que gerencia as tarefas.

class ToDoManager {
   val tasks : MutableList<ToDoTask> = mutableListOf()


   fun addToDo(name : String, description : String, dueDate : String) {
       tasks.add(ToDoTask(name, description, formatDate(dueDate)))
   }


   fun addTodo(input : String) {
       val splited = input.split(' ')
       val name = splited[0]
       val description = splited[1]
       val dueDate = splited[2]
       addToDo(name, description, dueDate)
   }


   private fun formatDate(date : String) : LocalDate {
       val formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy")
       return LocalDate.parse(date, formatter)
   }


   fun getNextTaskToExpire() : ToDoTask {
       return tasks.minBy { it.dueDate }
   }


   private fun getIndexByName(name : String) : Int {
       val index = tasks.binarySearchBy(name) { it.name }
       if (index < 0) throw Error("Tarefa nao existe")
       return index
   }


   fun getTaskByName(name : String) : ToDoTask {
       return tasks[getIndexByName(name)]
   }


   fun removeTask(name : String) {
       tasks.removeAt(getIndexByName(name))
   }


   fun clearTasks() {
       tasks.clear()
   }
}

A data class que representa uma tarefa, contendo informações como nome, descrição e data de vencimento  é a  ToDoTask:

import java.time.LocalDate


data class ToDoTask(
   val name : String,
   val description : String,
   val dueDate : LocalDate,
)

Essas duas classes foram adicionadas ao diretório src/main/kotlin. Agora vamos criar um arquivo de feature, adicioná-lo na pasta de resources e definir os cenários de teste utilizando a linguagem Gherkin. Para nosso exemplo, o cenário "O usuário posta uma tarefa" é descrito da seguinte forma:

Feature: O usuario consegue usar a ferramenta para gerenciar suas tarefas
 Scenario: O usuario posta uma tarefa
   Given tarefa A nao existe
   When usuario adiciona tarefa de nome A com descrição descricao com data 22/12/2024
   Then tarefa A deveria existir

Para executar os teste, crie na pasta de tests/kotlin a classe CucumberRunner.kt:

import org.junit.runner.RunWith
import io.cucumber.junit.Cucumber
import io.cucumber.junit.CucumberOptions


@RunWith(Cucumber::class)
@CucumberOptions(
   features = ["src/main/resources/features"]
)
class CucumberRunner

Mas ainda não está tudo pronto! Para que os testes sejam executados, precisamos definir as implementações dos steps (passos) especificados nos cenários de feature. Isso é feito na classe StepDefs (que deve ser adicionada na pasta em que está o CucumberRunner), onde cada step é associado a uma ação concreta na aplicação:

import io.cucumber.java8.En
import io.cucumber.java8.Scenario
import org.junit.Assert.assertEquals
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows




class StepDefs : En {
   private val manager : ToDoManager = ToDoManager()


   init {
      Before { scenario: Scenario ->
          manager.clearTasks()
      }


       Given("tarefa {} nao existe") { name: String ->
           assertThrows<Error> { manager.getTaskByName(name) }
       }


       When("usuario adiciona tarefa de nome {} com descrição {} com data {}") {
           name: String, description : String, date : String ->
           manager.addToDo(name, description, date)
       }


       Then("tarefa {} deveria existir") {
           name : String ->
           assertDoesNotThrow {
               val task = manager.getTaskByName(name)
               assertEquals(name, task.name)
           }
       }
   }


}

Conclusão editar

Este exemplo prático ilustra como o Cucumber se integra com a metodologia BDD, transformando cenários de teste escritos em linguagem natural em testes automatizados. A capacidade de descrever o comportamento desejado de uma aplicação em termos claros e compreensíveis não só facilita a comunicação entre membros técnicos e não técnicos da equipe, mas também garante que os requisitos do sistema sejam validados de maneira eficaz. Implementar o Cucumber em projetos de desenvolvimento de software pode ajudar significativamente na entrega de produtos de alta qualidade que atendem muito bem às necessidades dos usuários.

Referências:

https://medium.com/opanehtech/gherkin-e-cucumber-mapeando-os-testes-automatizados-53232bf26e79

https://cucumber.io/

https://coodesh.com/blog/dicionario/o-que-e-cucumber/

https://medium.com/brazilians-in-tech/conhecendo-a-ferramenta-cucumber-7e12db6a5703

https://dev.to/rod292/introducao-ao-cucumber-4jn8