# BDD (Behavior-Driven Development): Guia Completo para Equipes Ágeis

**Meta Description:** Aprenda BDD: Gherkin, Cucumber, Behave, e como implementar desenvolvimento guiado por comportamento para equipes ágeis.

---

## O Que é BDD?

Behavior-Driven Development (BDD) é uma evolução do TDD que foca na colaboração entre desenvolvedores, QA e negócios. BDD usa linguagem natural (Gherkin) para descrever comportamentos de software, tornando requisitos mais acessíveis a todos.

### A História do BDD

```
2003: Dan North cria "JBehave" (Java)
2006: Ruby implementation "Cucumber" (Aslak Hellesøy)
2008: GoBehave para Python
2012: Cucumber-JVM
Hoje: Gherkin é padrão indústria
```

---

## Gherkin: A Linguagem de BDD

### Estrutura Básica

```gherkin
# language: pt
Funcionalidade: Título da funcionalidade
  Como um [ator]
  Quero [ação]
  Para [benefício]

  Contexto: [precondições]
    Dado [estado inicial]
    E [mais estados]

  Cenário: [nome do cenário]
    Quando [ação]
    E [mais ações]
    Então [resultado esperado]
    E [mais resultados]

  Cenário: [outro cenário]
    ...
```

### Palavras-Chave Gherkin

| Keyword | Uso |
|---------|-----|
| `Funcionalidade` (Feature) | Agrupa cenários relacionados |
| `Contexto` (Background) | Precondições comuns |
| `Cenário` (Scenario) | Caso de uso específico |
| `Dado` (Given) | Pré-condições |
| `Quando` (When) | Ação/evento |
| `Então` (Then) | Resultado esperado |
| `E` (And) | Conjunção |
| `Mas` (But) | Conjunção negativa |
| `Esquema do Cenário` | Cenário parametrizado |
| ` Exemplos` (Examples) | Dados de teste |

### Exemplo Completo

```gherkin
# language: pt
Funcionalidade: Login de Usuário
  Como um usuário registrado no sistema
  Quero fazer login com minhas credenciais
  Para acessar minha conta e visualizar meus dados

  Contexto:
    Dado que o sistema está operacional
    E o usuário "joao@exemplo.com" está cadastrado com senha "Senha@123"

  Cenário: Login com credenciais válidas
    Quando eu acesso a página de login
    E preencho o campo email com "joao@exemplo.com"
    E preencho o campo senha com "Senha@123"
    E clico no botão "Entrar"
    Então sou redirecionado para o dashboard
    E uma mensagem de boas-vindas é exibida
    E meu nome "João Silva" aparece no cabeçalho

  Cenário: Login com senha incorreta
    Quando eu acesso a página de login
    E preencho o campo email com "joao@exemplo.com"
    E preencho o campo senha com "senhaerrada"
    E clico no botão "Entrar"
    Então permaneço na página de login
    E uma mensagem de erro "Credenciais inválidas" é exibida
    E o campo senha está vazio para nova tentativa

  Cenário: Login com email não cadastrado
    Quando eu acesso a página de login
    E preencho o campo email com "naoexiste@exemplo.com"
    E preencho o campo senha com "senha123"
    E clico no botão "Entrar"
    Então uma mensagem de erro "Usuário não encontrado" é exibida

  Esquema do Cenário: Bloqueio após múltiplas tentativas
    Quando tento fazer login com email "<email>" e senha "<senha>"
    E repito este login falho por <tentativas> vezes
    Então minha conta fica bloqueada por <minutos> minutos
    E uma mensagem "Conta temporariamente bloqueada" é exibida

    Exemplos:
      | email             | senha      | tentativas | minutos |
      | joao@exemplo.com  | errada1    | 3          | 30      |
      | maria@exemplo.com  | errada2    | 5          | 60      |
```

---

## Cucumber: Implementando BDD

### Cucumber Architecture

```
.feature files (Gherkin)
        ↓
   Cucumber Parser
        ↓
   Step Definitions (Glue Code)
        ↓
   Step Definitions (Java/JS/Python/Ruby)
        ↓
   Application Under Test
```

### Cucumber com Java (Spring Boot)

#### Dependências

```xml
<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-java</artifactId>
    <version>7.14.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-spring</artifactId>
    <version>7.14.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-junit-platform-engine</artifactId>
    <version>7.14.0</version>
    <scope>test</scope>
</dependency>
```

#### Feature File

```gherkin
# src/test/resources/features/carrinho.feature
Funcionalidade: Carrinho de Compras
  Como um cliente do e-commerce
  Quero adicionar e remover produtos do carrinho
  Para finalizar minha compra

  Contexto:
    Dado que estou logado como "cliente@teste.com"
    E o produto "Camiseta Azul" custa R$ 49,90
    E o produto "Calça Jeans" custa R$ 129,90
    E o produto "Tênis" custa R$ 199,90

  Cenário: Adicionar produto ao carrinho
    Quando adiciono "Camiseta Azul" ao carrinho
    Então o carrinho deve conter 1 item
    E o total deve ser R$ 49,90

  Cenário: Adicionar múltiplos produtos
    Quando adiciono "Camiseta Azul" ao carrinho
    E adiciono "Calça Jeans" ao carrinho
    E adiciono "Tênis" ao carrinho
    Então o carrinho deve conter 3 itens
    E o total deve ser R$ 379,70

  Cenário: Remover produto do carrinho
    Dado que tenho "Camiseta Azul" e "Calça Jeans" no carrinho
    Quando removo "Camiseta Azul" do carrinho
    Então o carrinho deve conter 1 item
    E o total deve ser R$ 129,90
```

#### Step Definitions

```java
package steps;

import io.cucumber.java.pt.*;
import org.springframework.beans.factory.annotation.Autowired;
import static org.junit.jupiter.api.Assertions.*;

class CarrinhoSteps {
    
    @Autowired
    private CarrinhoService carrinhoService;
    
    @Autowired
    private TestContext testContext;
    
    private Carrinho carrinho;
    
    @Dado("que estou logado como {string}")
    public void que_estou_logado_como(String email) {
        testContext.setUsuario(email);
        carrinho = new Carrinho();
    }
    
    @Dado("o produto {string} custa R$ {double}")
    public void produto_custa(String nome, double preco) {
        // Setup de produto no banco de dados de teste
    }
    
    @Quando("adiciono {string} ao carrinho")
    public void adiciono_produto_ao_carrinho(String produto) {
        carrinho.adicionar(new Item(produto, obterPreco(produto)));
    }
    
    @Então("o carrinho deve conter {int} item")
    public void carrinho_deve_conter_itens(int quantidade) {
        assertEquals(quantidade, carrinho.getItens().size());
    }
    
    @Então("o total deve ser R$ {double}")
    public void total_deve_ser(double total) {
        assertEquals(total, carrinho.getTotal(), 0.01);
    }
}
```

### Cucumber com Python (Behave)

#### Instalação

```bash
pip install behave
```

#### Feature File

```gherkin
# features/carrinho.feature
Funcionalidade: Carrinho de Compras
  Como um cliente do e-commerce
  Quero adicionar produtos ao carrinho
  Para visualizar o total da compra

  Cenário: Adicionar produto ao carrinho
    Dado que o produto "Camiseta" custa 50.00
    Quando adiciono o produto ao carrinho
    Então o total deve ser 50.00
```

#### Step Definitions

```python
# features/steps/carrinho_steps.py
from behave import given, when, then
from carrinho import Carrinho

@given('o produto "{nome}" custa {preco}')
def step_impl(context, nome, preco):
    if not hasattr(context, 'produtos'):
        context.produtos = {}
    context.produtos[nome] = float(preco.replace('.', '').replace(',', '.'))

@when('adiciono o produto ao carrinho')
def step_impl(context):
    if not hasattr(context, 'carrinho'):
        context.carrinho = Carrinho()
    
    for nome, preco in context.produtos.items():
        context.carrinho.adicionar(nome, preco)

@then('o total deve ser {total}')
def step_impl(context, total):
    esperado = float(total.replace('.', '').replace(',', '.'))
    assert context.carrinho.total == esperado, \
        f"Esperado {esperado}, got {context.carrinho.total}"
```

#### Runner

```python
# features/environment.py
def before_all(context):
    context.produtos = {}
    context.carrinho = None

def after_scenario(context, scenario):
    # Cleanup
    context.produtos = {}
    context.carrinho = None
```

---

## BDD em Equipes Ágeis

### O Ciclo BDD Completo

```
   ┌──────────────────────────────────────────────┐
   │                                              │
   ▼                                              │
┌───────┐    ┌─────────┐    ┌──────────┐    ┌─────┴───┐
│DISCUSS│───▶│EXAMPLES │───▶│AUTOMATE │───▶│IMPLEMENT│
│   ()  │    │   (O)   │    │   (o)   │    │   (.)   │
└───────┘    └─────────┘    └──────────┘    └─────────┘
    ▲                                              │
    │                                              │
    └──────────────────────────────────────────────┘
                    (Feedback)
```

### Reunião de Three Amigos

A reunião de Three Amigos junta desenvolvedores, QA e product owner para discutir requisitos.

```markdown
# Agenda da Reunião Three Amigos

## Preparação (1 dia antes)
- PO compartilha user stories
- QA prepara perguntas
- Devs revisam história

## Reunião (60 minutos)
1. PO apresenta user story (10 min)
2. Discussão de requisitos (20 min)
3. QA identifica cenários de teste (15 min)
4. Devs identificam complexidades (10 min)
5. Acordo sobre exemplos concretos (5 min)

## Output
- User story com critérios de aceitação claros
- Cenários BDD definidos
- Incertezas documentadas
```

### Exemplo: User Story com BDD

```markdown
## User Story: RS-123 - Carrinho Abandonado

### Como
  Vendedor do e-commerce

### Eu quero
  Receber notificação quando cliente abandonar carrinho

### Para que
  Possa entrar em contato e recuperar a venda

### Critérios de Aceitação:
- [ ] Notificação enviada 30 min após abandono
- [ ] Email inclui produtos abandonados
- [ ] Email inclui link para recuperação
- [ ] Não enviar se cliente já Comprou
- [ ] Rate limit de 1 email por cliente por dia

### Cenários BDD:
```

```gherkin
Funcionalidade: Carrinho Abandonado
  
  Cenário: Notificação enviada após 30 minutos
    Dado que o cliente adicionou produtos ao carrinho
    E saiu do site sem Comprar
    Quando passam 30 minutos
    Então um email de recuperação é enviado
  
  Cenário: Email inclui produtos abandonados
    Dado que o cliente abandonou o carrinho com:
      | Produto       | Quantidade |
      | Camiseta     | 2         |
      | Calça Jeans  | 1         |
    Quando o email de recuperação é enviado
    Então o email lista todos os produtos abandonados
  
  Cenário: Não enviar se cliente Comprou
    Dado que o cliente abandonou o carrinho
    Mas depois finalizou a compra
    Quando passam 30 minutos
    Então nenhum email é enviado
```

---

## Boas Práticas em BDD

### 1. Feature Files Bem Estruturados

```gherkin
# BOM: Cenários focados e descritivos
Funcionalidade: Cálculo de Frete
  Cenário: Frete para SP capital
    Dado que o produto custa R$ 100
    Quando o cliente é de "SP" e "São Paulo"
    Então o frete é R$ 15,90

# RUIM: Cenário muito genérico
Funcionalidade: Frete
  Cenário: Teste de frete
    Dado que tenho um produto
    Quando calculo o frete
    Então deve funcionar
```

### 2. Step Definitions Reutilizáveis

```python
# Defina steps genéricos
@given('que o produto "{nome}" custa R$ {preco}')
def step_produto(context, nome, preco):
    context.produtos[nome] = float(preco)

@when('eu adiciono "{nome}" ao carrinho')
def step_adicionar(context, nome):
    context.carrinho.adicionar(nome, context.produtos[nome])
```

### 3. Page Objects para Web

```python
# pages/login_page.py
class LoginPage:
    def __init__(self, driver):
        self.driver = driver
    
    @property
    def email_field(self):
        return self.driver.find_element(By.ID, 'email')
    
    @property
    def password_field(self):
        return self.driver.find_element(By.ID, 'password')
    
    @property
    def login_button(self):
        return self.driver.find_element(By.ID, 'login-button')
    
    def login(self, email, password):
        self.email_field.send_keys(email)
        self.password_field.send_keys(password)
        self.login_button.click()
```

---

## Integração com CI/CD

```yaml
# GitHub Actions - BDD Tests
name: BDD Tests

on: [push, pull_request]

jobs:
  bdd-tests:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      
      - name: Install dependencies
        run: |
          pip install behave selenium webdriver-manager
      
      - name: Run BDD tests
        run: behave --format=json --outfile=reports/behave.json
      
      - name: Upload reports
        uses: actions/upload-artifact@v4
        with:
          name: cucumber-reports
          path: reports/
```

---

## Conclusão

BDD é uma metodologia poderosa que une equipes através de linguagem comum. As chaves para sucesso são:

1. **Colaboração** - Three Amigos regularmente
2. **Exemplos concretos** - Ao invés de requisitos vagos
3. **Automação** - Transforma cenários em testes executáveis
4. **Documentação viva** - Features são especificação + teste
5. **Feedback rápido** - Ciclos curtos de desenvolvimento

---

### FAQ

**P: BDD substitui TDD?**  
R: Não. BDD usa TDD internamente. BDD foca em colaboração, TDD em técnica.

**P: Como começar com BDD?**  
R: Comece com Three Amigos para definir cenários, depois implemente com Cucumber/Behave.

**P: Quantos cenários por feature?**  
R: O suficiente para cobrir comportamento. Evite redundância, use Examples para variações.

**P: BDD funciona para qualquer projeto?**  
R: Melhor para projetos com requisitos claros e colaboração entre negocio e TI.
