TDD
BDD
Testes Automatizados
Jest
Cypress
Qualidade de Código

Automated Tests: TDD and BDD in Practice

Automated Tests: TDD and BDD in Practice

Testing is the foundation of reliable software. When applied well, they reduce bugs, increase delivery speed and give confidence to refactor. Two popular paradigms are Test-Driven Development (TDD) and Behavior-Driven Development (BDD). Although complementary, they have different focuses.

When to use TDD vs BDD

  • TDD: focus on code units (functions, classes). You write the test before implementation, ensuring that the public API behaves as expected.
  • BDD: focus on high-level behavior (user flows, requirements). Uses almost natural language (Gherkin) to describe scenarios.

Rule of thumb: use TDD for business logic and internal libraries; use BDD for UI flows and integrations.

Recommended tools

LayerToolWhy use
Unitary (JS/TS)JestFast, snapshot testing, integrated coverage
Unitary (Node)Mocha + ChaiFlexible, good integration with Sinon
UI (React)Testing LibraryTest the UI as the user sees it
End-to-endCypressReal browser testing, visual debugging
BDDCucumber.jsGherkin syntax, Jest/Cypress integration

TDD flow step by step

  1. Write the test that fails (red).
  2. Implement minimal code to pass (green).
  3. Refactor keeping the tests green (refactor).
  4. Repeat.

Practical example, Price formatting function

// priceFormatter.test.ts (Jest) import { formatPrice } from './priceFormatter'; test('formata número como moeda BRL', () => { expect(formatPrice(1234.5)).toBe('R$ 1.234,50'); });
// priceFormatter.ts (implementação mínima) export function formatPrice(value: number): string { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(value); }

BDD flow with Cucumber.js

Scenario definition (Gherkin)

Feature: Cadastro de Usuário As a visitor I want to create an account So that I can access protected features Scenario: Cadastro bem-sucedido Given I am on the registration page When I fill the form with valid data And I submit the form Then I should see a confirmation message And I receive a verification email

Implementation of steps (Cypress + Cucumber)

import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'; Given('I am on the registration page', () => { cy.visit('/register'); }); When('I fill the form with valid data', () => { cy.get('#email').type('usuario@example.com'); cy.get('#password').type('SenhaForte123!'); cy.get('#confirmPassword').type('SenhaForte123!'); }); When('I submit the form', () => { cy.get('form').submit(); }); Then('I should see a confirmation message', () => { cy.contains('Cadastro concluído').should('be.visible'); });

General good practices

  • Keep tests fast: if a test takes more than 500ms, it is probably doing unnecessary I/O.
  • Isolation: use mocks/stubs for external dependencies (APIs, banks).
  • Minimum coverage: 80% line coverage is a good starting point, but prioritize critical logic.
  • Continuous integration: configure the pipeline (GitHub Actions, GitLab CI) to run npm test on each PR.
  • Visual feedback: use IDE plugins that show real-time test results.

Implementation checklist

  • Choose testing framework (Jest, Cypress, etc.)
  • Configure jest.config.js and cypress.json
  • Create directories tests/unit and tests/e2e
  • Write first failed test for each new feature
  • Integrate tests into the CI pipeline
  • Monitor coverage and fallback failures

Conclusion

TDD and BDD are not just techniques, they are mindset changes. When adopted correctly, they ensure that your code evolves without fear of breaking existing functionality. Start small, write clear tests, and let them guide your development.


What is your experience with TDD or BDD? Share in the comments!

Also read