Testes em PHP: unit, integration, e2e do A ao Z

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que testar em PHP não é uma opção, mas um padrão

No desenvolvimento PHP moderno, os testes há muito deixaram de ser "boa prática" e se tornaram uma etapa obrigatória em projetos de produção. Sem cobertura de código com testes, você corre o risco de lançar em produção um erro que pode custar dinheiro e reputação ao negócio. Neste artigo, vamos analisar três níveis de teste: unit (unitário), integration (integração) e e2e (ponta a ponta). Você aprenderá como eles diferem, quais ferramentas usar (PHPUnit, Pest, Laravel Dusk, Codeception) e como construir uma estratégia de teste adequada para seu projeto PHP.



1. Testes Unitários: testando unidades isoladas de código

Testes unitários verificam o funcionamento de classes, funções ou métodos individuais isolados de dependências externas (BD, API, sistema de arquivos). Este é o tipo de teste mais rápido e barato. A principal ferramenta em PHP é o PHPUnit (padrão de fato) e sua alternativa "moderna" Pest.



1.1. Instalação e primeiro teste com PHPUnit

Instale o PHPUnit via Composer:

composer require --dev phpunit/phpunit

Crie um teste para uma classe calculadora simples:

<?php// src/Calculator.phpclass Calculator {    public function add(int $a, int $b): int {        return $a + $b;    }}

// tests/CalculatorTest.phpuse PHPUnit\\Framework\\TestCase;

class CalculatorTest extends TestCase { public function testAddition(): void { $calc = new Calculator(); $result = $calc->add(2, 3); $this->assertEquals(5, $result); }}

Execute o teste:

./vendor/bin/phpunit tests


1.2. Uso de Objetos Mock

Para isolar a classe sendo testada, "substituímos" suas dependências usando mocks. Exemplo com um repositório de usuários:

<?phpclass UserService {    private UserRepository $repo;    public function __construct(UserRepository $repo) {        $this->repo = $repo;    }    public function getUserName(int $id): string {        $user = $this->repo->findById($id);        return $user ? $user->getName() : 'Guest';    }}

// No teste$mockRepo = $this->createMock(UserRepository::class);$mockRepo->method('findById') ->with(1) ->willReturn(new User('Alice'));

$service = new UserService($mockRepo);$this->assertEquals('Alice', $service->getUserName(1));

Best practice: Escreva testes unitários para toda a lógica de negócios. Eles devem ser executados em segundos e não depender do ambiente.



2. Testes de Integração: verificando a interação com BD, API e serviços externos

Testes de integração verificam como suas classes funcionam juntas com componentes reais: banco de dados, cache, serviços HTTP externos. Eles são mais lentos que os testes unitários, mas fornecem mais confiança de que o sistema funciona como um todo unificado.



2.1. Testando o trabalho com banco de dados (Laravel + RefreshDatabase)

Se você usa Laravel, os testes de integração se tornam muito simples graças ao trait RefreshDatabase:

<?phpnamespace Tests\\Feature;

use Tests\\TestCase;use Illuminate\\Foundation\\Testing\\RefreshDatabase;

class UserRegistrationTest extends TestCase { use RefreshDatabase;

public function test_user_can_register(): void { $response = $this->post('/register', [ 'name' => 'John', 'email' => 'john@example.com', 'password' => 'secret123', ]);

$response->assertStatus(302); // redirect after success $this->assertDatabaseHas('users', [ 'email' => 'john@example.com' ]); }}

O trait RefreshDatabase migra automaticamente o BD antes dos testes e

Blogs

Book Recommendations