MÓDULO 02 · CONCEITO 04 DE 8

BDD & Given/When/Then

Testes como especificação executável — quando funciona maravilhosamente e quando vira teatro.

Tempo de leitura ~20 min Pré-requisito Test doubles Próximo Property-based testing

Em 2003, Dan North começou a escrever sobre uma frustração específica de ensinar TDD: alunos travavam não na mecânica do ciclo, mas em decisões como "o que devo testar primeiro?", "que nome dar?", "como sei se cobri o bastante?". TDD nada disso prescrevia. North percebeu que o vocabulário do TDD — o uso da palavra test em todo lugar — desviava o foco do problema real, que era especificação de comportamento. Daí veio o Behavior-Driven Development (BDD): uma evolução do TDD que substituía vocabulário e introduzia a fórmula Given/When/Then. Não é uma tecnologia diferente; é uma forma diferente de pensar e nomear.

A ideia central de BDD: testes deveriam ler como especificações executáveis do comportamento esperado. "Given a customer with $100 in their account, when they withdraw $30, then their balance should be $70." Essa estrutura, quando aplicada com integridade, faz os testes serem documentação viva — alguém que nunca viu o código consegue ler os testes e entender o que o sistema faz. E quando vira fluência, muda como você pensa o problema antes mesmo de escrever código.

O que motivou BDD

North observou três problemas recorrentes em times tentando praticar TDD:

  1. Confusão sobre o que testar: alunos não sabiam por onde começar. "Test the class? Test methods? Test the API?". TDD clássico não dava resposta.
  2. Nomes ruins: testFunction1(), testHappyPath(), testValidation(). Nomes descreviam mecânica, não comportamento. Em três meses, ninguém sabia o que cada teste verificava sem ler o corpo.
  3. Alienação de stakeholders: testes eram escritos por devs, em código, longe de quem definia requisitos. Conversa entre negócio e dev acontecia em documentos paralelos que ficavam desatualizados.

BDD endereçou os três:

Given/When/Then — a fórmula

A estrutura de cada cenário tem três partes:

A fórmula força clareza. Se você não consegue articular o cenário em G/W/T, há boa chance de não saber direito o que está testando. É ferramenta de pensamento.

O mesmo no nível de código (sem framework)

Você não precisa de Cucumber ou SpecFlow para aplicar G/W/T. Pode ser apenas estrutura mental para o teste, com comentários explícitos:

[Fact]
public void Withdrawing_Decreases_Balance() {
    // Given
    var account = new Account(initialBalance: 100);

    // When
    account.Withdraw(30);

    // Then
    account.Balance.Should().Be(70);
}

Isto é BDD-style sem ferramentas extras. Variantes comuns no mundo C# usam // Arrange / Act / Assert; em Python frequentemente omitem comentários e fazem por estrutura visual; em Go é "table-driven" onde cada linha é um cenário. Todas são variações do mesmo princípio.

Gherkin e os frameworks BDD

Quando o time inclui stakeholders no processo, surge a necessidade de uma sintaxe que negócio consiga ler e escrever. Gherkin é essa sintaxe: cenários em texto plano, em estrutura padrão, depois ligados a código por step definitions.

Feature: Account withdrawal
  As an account holder
  I want to withdraw money
  So that I can use it

  Scenario: Successful withdrawal
    Given an account with balance 100
    When I withdraw 30
    Then the balance should be 70

  Scenario: Insufficient funds
    Given an account with balance 100
    When I withdraw 200
    Then the withdrawal should fail
    And the balance should remain 100

Step definitions ligam cada linha em texto a código:

// C# com SpecFlow
[Given(@"an account with balance (\d+)")]
public void GivenAccountWithBalance(int balance) {
    _account = new Account(balance);
}

[When(@"I withdraw (\d+)")]
public void WhenIWithdraw(int amount) {
    _result = _account.Withdraw(amount);
}

[Then(@"the balance should be (\d+)")]
public void ThenBalanceShouldBe(int expected) {
    _account.Balance.Should().Be(expected);
}

Frameworks principais por linguagem: Cucumber (criado em Ruby, hoje multi-linguagem), SpecFlow (.NET, agora Reqnroll após mudança de mantenedor), behave (Python), godog (Go), pytest-bdd (Python alternativa, integrada ao pytest). Todos consomem Gherkin com pequenas variações.

Onde BDD com Gherkin brilha

O ferramental compensa em situações específicas:

Onde BDD vira teatro

Em outros contextos, Gherkin é overhead pesado que produz testes piores que os equivalentes em código direto. Sintomas de BDD mal-aplicado:

Stakeholder não escreve nem lê os cenários

Se devs estão escrevendo Gherkin para devs lerem, você adicionou uma camada de tradução sem ganho. Os mesmos testes em xUnit ou pytest seriam mais diretos. BDD-em-Gherkin custa o engajamento real do negócio; sem ele, é cerimônia.

Steps quase iguais multiplicando-se

"Given user with email john@x.com", "Given user with email mary@y.com", "Given user that has no email"... Cada variação vira um step novo. Gherkin força frases naturais; código permite parametrização limpa. Em projetos com muitas variações, testes ficam mais curtos e claros em código.

Indireção desnecessária

Para entender o que um cenário Gherkin testa, você precisa ler o cenário, encontrar os steps no código, e ler eles. Para entender um teste em xUnit, você lê o teste. Para casos onde o ganho de legibilidade-pelo-stakeholder não existe, a indireção é puro custo.

Lentidão de execução

Frameworks BDD adicionam parsing de Gherkin, matching de regex, reflection. Em suítes grandes, isso vira centenas de milissegundos por teste — somando minutos no total. Para suítes em Tier 1 do CI, é problema.

A regra prática: se o time tem stakeholders ativos no processo e o domínio tem regras de negócio complexas, BDD com Gherkin paga. Caso contrário, G/W/T como estrutura mental dentro de testes em código colhe a maior parte do benefício sem o overhead.

armadilha de adoção

Times adotam Gherkin "porque é melhor prática" sem stakeholders comprados. Resultado típico: dois meses depois, devs estão escrevendo e mantendo Gherkin sozinhos, e ninguém do negócio nunca abriu os arquivos. Custou a adoção, custou velocidade, sem ganho. Se o motivo de usar Gherkin é "deveríamos ter testes legíveis para o time", comece sem Gherkin — código bem nomeado já cobre 90%.

O lado mais valioso de BDD — a conversa

Frequentemente esquecido: BDD não é primariamente sobre ferramentas. É sobre conversas estruturadas entre negócio e tech antes de codar. A prática que North chama de "Three Amigos" — produto, dev e QA discutindo cada cenário antes da implementação — é onde acontece a maior parte do valor.

Nessa conversa:

Esses cenários — escritos em Gherkin ou em qualquer outro formato — viram a especificação compartilhada. Quando o dev volta para implementar, sabe exatamente o que precisa fazer. Quando o QA testa, sabe o que verificar. Quando produto valida, sabe o que esperar.

O ponto é: você pode ter essa conversa sem usar Cucumber. A conversa é o valor. O ferramental ajuda quando ele alimenta a conversa e dificulta quando ele a substitui por cerimônia.

Acceptance criteria — o nível imediatamente acima

Antes de cenários BDD, há acceptance criteria em stories/tickets — listas de condições que precisam ser atendidas para a story ser considerada pronta. AC bem-escrita já tem estrutura G/W/T implícita:

Story: User can withdraw from account

Acceptance Criteria:
- Given an account with sufficient balance,
  when user withdraws an amount,
  then balance is decreased by that amount
  and a transaction record is created.

- Given an account with insufficient balance,
  when user attempts withdrawal,
  then the operation fails
  and balance is unchanged
  and the user sees error message "Insufficient funds".

- Given an account that is locked (suspect activity),
  when user attempts any withdrawal,
  then the operation fails
  and the user sees "Account locked, contact support".

Essa AC é executável conceitualmente — vira teste 1:1. Times maduros escrevem AC nesse formato como prática padrão (em Jira, Linear, etc). Quando alguém quer formalizar, vira Gherkin trivial. Quando o time prefere testes em código, viram [Fact] ou def test_* com a mesma estrutura.

BDD em testes de aceitação E2E

Onde BDD com Gherkin se mantém forte mesmo em times sem BA é em testes de aceitação end-to-end. Esses testes são tipicamente poucos (dezenas, não centenas), focados em fluxos críticos, e revisados por produto. O custo de Gherkin se dilui, e a documentação viva tem público real.

Feature: Order checkout

  Scenario: User completes purchase with valid card
    Given a user logged in with cart containing a $50 item
    When they enter valid card details and submit checkout
    Then the order is created with status "confirmed"
    And a confirmation email is sent to the user
    And the cart is emptied

  Scenario: Card declined
    Given a user logged in with cart containing a $50 item
    When they enter card details for a card that will be declined
    Then the order is not created
    And the user sees "Payment declined - try another card"
    And the cart still contains the $50 item

Cenários assim viram suíte E2E pequena, executada em pre-deploy, e legível por produto/QA/dev. Um pouco de Gherkin onde ele ajuda; sem Gherkin no resto.

Como praticar

  1. Reescreva nomes de testes existentes em estilo BDD. Pegue 10 testes seus. Renomeie de test_validate_order para order_should_fail_when_total_exceeds_limit. Note como o nome agora é a especificação.
  2. Aplique G/W/T como estrutura, não Gherkin. Pegue uma feature do seu projeto. Antes de implementar, escreva 5 cenários em texto plano com G/W/T. Implemente. Note como o esforço de articular antecipa decisões de design.
  3. Experimente Gherkin num caso pequeno. Configure SpecFlow/behave/godog num projeto pequeno. Escreva 2-3 cenários. Sinta o overhead. Decida com evidência se vale para seu contexto.

Referências para aprofundar

  1. livro BDD in Action (2nd ed.) — John Ferguson Smart (2023). Tratamento moderno de BDD com Cucumber. Capítulos sobre Three Amigos e specification by example são valiosos.
  2. livro Specification by Example — Gojko Adzic (2011). Não usa o termo "BDD" mas é fundacional. Como times reais derivam testes de exemplos concretos. Padrão da indústria.
  3. livro The Cucumber Book (2nd ed.) — Wynne & Hellesoy (2017). Manual definitivo do Cucumber. Para quem decidir adotar Gherkin com seriedade.
  4. artigo Introducing BDD — Dan North (2006). dannorth.net/introducing-bdd/ — texto fundacional. Conta a origem e a motivação. Curto, formativo.
  5. artigo What's in a Story? — Dan North (2007). dannorth.net/whats-in-a-story/ — formato de story que North propõe. Inclui acceptance criteria executáveis.
  6. artigo The 3 Amigos — George Dinwiddie. georgedinwiddie.com — explicação clara da prática que estrutura conversas BDD.
  7. artigo Given-When-Then is Two Things — Liz Keogh. lizkeogh.com — Keogh é referência em BDD. Argumenta que G/W/T é mais sobre conversa do que sobre formato.
  8. docs Cucumber Documentation. cucumber.io/docs — fonte oficial multi-linguagem. Veja seções sobre best practices.
  9. docs Reqnroll Documentation. docs.reqnroll.net — sucessor open-source do SpecFlow para .NET, mantido pela comunidade. Use este, não SpecFlow legacy.
  10. docs pytest-bdd Documentation. pytest-bdd.readthedocs.io — alternativa que integra Gherkin ao pytest. Menos cerimonial que behave.
  11. vídeo BDD - Common Misconceptions — Liz Keogh. YouTube. Crítica útil de BDD mal-aplicado. O que BDD não é e por que muitos times se confundem.
  12. vídeo The Three Amigos — George Dinwiddie (Agile2009). YouTube. Apresentação seminal sobre a prática. Foco em colaboração estruturada.