Por que o TDD se tornou padrão para desenvolvedores PHP?
Imagine: você escreve código, executa, vê um erro, corrige — e assim por diante. Familiar? Agora imagine que você primeiro escreve um teste que certamente falhará, depois o código mínimo para fazê-lo passar, e só então refatora. Isso é TDD em PHP — desenvolvimento orientado a testes, que transforma o caos em um sistema organizado.
Muitos desenvolvedores temem o TDD: "Isso vai desacelerar o desenvolvimento!", "Não sei como testar código legado", "PHPUnit é complicado". Mas na prática, o TDD economiza horas de depuração e torna o código resiliente a mudanças. Neste artigo, vamos explorar o TDD com exemplos reais em PHP, mostrar como funciona o ciclo "vermelho-verde-refatoração" e fornecer modelos prontos para implementação.
O que é TDD e como funciona em PHP?
Desenvolvimento Orientado a Testes (Test-Driven Development) é uma metodologia onde os testes são escritos antes da implementação. O ciclo básico é:
- Vermelho — escrevemos um teste que falha (esperamos um erro).
- Verde — escrevemos o código mínimo para o teste passar.
- Refatoração — melhoramos o código sem alterar o comportamento.
Em PHP, para TDD, o mais comum é usar PHPUnit — um poderoso framework para testes unitários. Mas TDD não é sobre ferramentas, e sim sobre disciplina. Vamos ver como funciona na prática.
Exemplo 1: Testando uma calculadora simples
Suponha que precisamos de uma função de soma de dois números. Sem TDD, escreveríamos:
function add($a, $b) { return $a + $b;}echo add(2, 3); // 5Com TDD, primeiro escrevemos o teste:
use PHPUnit\\Framework\\TestCase;
class CalculatorTest extends TestCase { public function testAdd() { $calculator = new Calculator(); $result = $calculator->add(2, 3); $this->assertEquals(5, $result); }}Executamos — o teste falha (vermelho). Escrevemos a implementação mínima:
class Calculator { public function add($a, $b) { return $a + $b; }}O teste passa (verde). Refatoração não é necessária — o código é simples. Mas se quiséssemos adicionar tratamento para números negativos, primeiro escreveríamos um teste para esse caso.
Exemplo 2: TDD para trabalhar com banco de dados
Muitas vezes dizem: "TDD não é adequado para BD". Isso é um mito. Use mocks e bancos de dados de teste. Vejamos um exemplo com UserRepository:
class UserRepositoryTest extends TestCase { public function testFindUserById() { $pdoMock = $this->createMock(PDO::class); $stmtMock = $this->createMock(PDOStatement::class); $pdoMock->method('prepare') ->willReturn($stmtMock); $stmtMock->method('fetch') ->willReturn(['id' => 1, 'name' => 'Alex']); $repository = new UserRepository($pdoMock); $user = $repository->findById(1); $this->assertEquals('Alex', $user['name']); }}O teste verifica se o repositório chama o SQL corretamente e processa o resultado. O código de implementação será mínimo: apenas executar a consulta e retornar os dados.
Ferramentas populares para TDD em PHP
Para que o TDD se torne parte do seu workflow, você precisa dominar algumas ferramentas:
- PHPUnit — framework principal para testes. Instalação:
composer require --dev phpunit/phpunit. - Mockery — biblioteca para criar mocks com API flexível.
- Prophecy — alternativa ao Mockery, frequentemente usada com Symfony.
- PHPStan / Psalm — análise estática que complementa o TDD, encontrando erros antes da execução dos testes.
Para testes de integração, você pode usar Laravel Dusk ou Symfony Panther, mas para começar, bas