Testar software é uma prática essencial para garantir que seu código funcione como esperado, especialmente à medida que o projeto cresce. Nesta aula, vamos mergulhar no mundo dos testes em PHP, começando pelos conceitos fundamentais e chegando à prática com PHPUnit, a ferramenta mais utilizada no ecossistema PHP.

Você vai entender por que testar é tão importante, conhecer os diferentes tipos de testes (unitários, de integração, funcionais, etc.), e aprender a configurar e escrever seus primeiros testes com PHPUnit. Ao final, terá uma base sólida para incorporar testes em seus projetos profissionais.

Por que testar

Testar é uma forma de verificar se o código produz os resultados esperados, mas vai muito além disso. Testes bem escritos servem como documentação viva, mostram como as funções e classes devem ser usadas, e dão confiança para refatorar e adicionar novas funcionalidades sem medo de quebrar o que já funciona.

Imagine que você está desenvolvendo um sistema de e-commerce e precisa alterar a regra de cálculo de frete. Sem testes, você teria que testar manualmente todas as combinações possíveis de endereço e peso, o que é inviável. Com testes automatizados, basta executar o comando de teste e verificar se tudo continua passando. Isso economiza tempo e evita regressões.

Tipos de teste

Existem vários níveis de teste, cada um com um propósito específico. Os principais são:

  • Testes unitários: verificam o funcionamento de uma unidade isolada do código, geralmente um método ou função. São rápidos e devem ser numerosos.
  • Testes de integração: verificam se diferentes partes do sistema funcionam juntas, como a comunicação com um banco de dados ou uma API externa.
  • Testes funcionais: testam o sistema como um todo, simulando a interação do usuário com a aplicação, muitas vezes via HTTP.
  • Testes de aceitação: validam se o software atende aos requisitos de negócio, geralmente escritos em uma linguagem próxima do cliente.

Nesta aula, focaremos nos testes unitários, que são a base de uma boa estratégia de testes. Eles são mais simples de escrever e executar, e ajudam a manter a qualidade do código no nível mais baixo.

PHPUnit (visão geral)

PHPUnit é o framework de testes mais popular para PHP. Ele segue o padrão xUnit, que é uma arquitetura comum em várias linguagens. Com PHPUnit, você escreve classes de teste que estendem PHPUnit\Framework\TestCase e usa métodos de asserção para verificar se os resultados são os esperados.

Para instalar o PHPUnit, você pode usar o Composer, o gerenciador de dependências do PHP. O comando abaixo instala o PHPUnit como dependência de desenvolvimento:

composer require --dev phpunit/phpunit

Depois de instalado, você pode executar os testes com o comando vendor/bin/phpunit. O PHPUnit procura por arquivos de teste em um diretório especificado (geralmente tests) e executa todos os métodos que começam com test.

Primeiro teste

Vamos criar nosso primeiro teste. Suponha que temos uma classe Calculadora com um método somar. Primeiro, criamos a classe em um arquivo src/Calculadora.php:

<?php

class Calculadora
{
    public function somar(float $a, float $b): float
    {
        return $a + $b;
    }
}

Agora, criamos o teste em tests/CalculadoraTest.php. O teste deve estender PHPUnit\Framework\TestCase e conter um método público que começa com test ou anotado com @test:

<?php

use PHPUnit\Framework\TestCase;

class CalculadoraTest extends TestCase
{
    public function testSomar()
    {
        $calc = new Calculadora();
        $resultado = $calc->somar(2, 3);
        $this->assertEquals(5, $resultado);
    }
}

Neste teste, estamos verificando que ao somar 2 e 3, o resultado é 5. O método assertEquals compara o valor esperado (5) com o valor real ($resultado). Se forem diferentes, o teste falha.

Para executar, basta rodar vendor/bin/phpunit na raiz do projeto. Se tudo estiver correto, você verá uma saída como:

PHPUnit 10.5.0 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 00:00.001, Memory: 6.00 MB

OK (1 test, 1 assertion)

Boas práticas

Ao escrever testes, siga estas boas práticas:

  • Escreva testes pequenos e focados em um único comportamento.
  • Use nomes descritivos para os métodos de teste, explicando o que está sendo verificado.
  • Evite dependências externas nos testes unitários (como banco de dados ou rede); use mocks ou stubs quando necessário.
  • Mantenha os testes independentes entre si, para que possam ser executados em qualquer ordem.
  • Execute os testes com frequência, de preferência após cada alteração no código.

Referências

Exercícios

  1. Crie uma classe `Subtracao` com um método `subtrair` que subtrai dois números. Escreva um teste PHPUnit que verifique se `subtrair(10, 4)` retorna 6.

    ✓ Resposta:
    <?php
    
    class Subtracao
    {
        public function subtrair(float $a, float $b): float
        {
            return $a - $b;
        }
    }
    
    // tests/SubtracaoTest.php
    
    use PHPUnit\Framework\TestCase;
    
    class SubtracaoTest extends TestCase
    {
        public function testSubtrair()
        {
            $sub = new Subtracao();
            $this->assertEquals(6, $sub->subtrair(10, 4));
        }
    }
  2. O que acontece se você esquecer de estender `PHPUnit\Framework\TestCase` em sua classe de teste? Explique.

    ✓ Resposta: Se a classe de teste não estender `PHPUnit\Framework\TestCase`, o PHPUnit não a reconhecerá como uma classe de teste válida. Os métodos `test*` não serão executados e você receberá um aviso de que nenhum teste foi encontrado.
  3. Escreva um teste que verifique se uma string `"Hello"` possui comprimento 5, usando `assertSame`.

    ✓ Resposta:
    use PHPUnit\Framework\TestCase;
    
    class StringTest extends TestCase
    {
        public function testComprimento()
        {
            $this->assertSame(5, strlen("Hello"));
        }
    }
  4. Qual a diferença entre `assertEquals` e `assertSame`? Dê um exemplo onde a diferença é relevante.

    ✓ Resposta: `assertEquals` verifica se os valores são iguais, mas não se os tipos são idênticos. `assertSame` verifica se os valores são idênticos, ou seja, mesmo valor e mesmo tipo. Exemplo: assertEquals(1, "1") passa, mas assertSame(1, "1") falha.
  5. Como você executaria apenas um método de teste específico em um arquivo de teste?

    ✓ Resposta: Você pode usar a opção `--filter` para filtrar por nome do método. Exemplo: vendor/bin/phpunit --filter testSomar executa apenas o método `testSomar`.