Alura > Cursos de Programação > Cursos de PHP > Conteúdos de PHP > Primeiras aulas do curso PHP e TDD: testes com PHPUnit

PHP e TDD: testes com PHPUnit

Por que testar? - Introdução

Olá, seja muito bem vindo(a) à Alura! Meu nome é Vinicius Dias e eu serei seu guia nesse treinamento de introdução aos Testes de Unidade com PHP. Antes de entrarmos propriamente ao assunto, vamos a uma pergunta: em algum momento você já escreveu um código que não funciona? Eu já, e muitas vezes só descobri isso quando o código já estava em produção, sendo executado pelo cliente. Essa é uma situação desagradável, afinal não queremos ter um cliente insatisfeito.

Existem algumas formas de mitigar esse problema, e a principal delas seria testarmos mais o nosso sistema. Entretanto, testes levam tempo, e sabemos que tempo é dinheiro. Imagina termos que testar todo o sistema a cada nova funcionalidade, já que ela tem o potencial de quebrar várias outras (esmo que não sejam muito relacionadas)?

Refletindo sobre esse cenário, é interessante termos testes automatizados. Mas antes de abordarmos a automatização, você sabe o que são testes de unidade (ou testes unitários)? São simplesmente testes que verificam o nosso código, ignorando se nosso visual está bonito ou se o banco de dados está funcionando.

Inclusive, existe um conceito chamado pirâmide de testes, e ela indica a proporção de testes que precisamos escrever. Na base da pirâmide, que é a parte mais larga, se encontram os testes de unidade, afinal eles são mais rápidos de executar, são mais baratos e mais fáceis de escrever e tão um feedback instantâneo. Sendo assim, se tivermos quebrado alguma coisa no código, perceberemos imediatamente.

Futuramente, você também poderá estudar testes de integração, de interface, entre outros, mas esse treinamento focará precisamente em testes de unidade. Tendo entendido esse conceito e os motivos para testar, vamos conhecer o projeto que desenvolveremos ao longo do curso.

A ideia é conseguirmos executar, com apenas um comando, vários métodos de testes que farão diversas verificações no nosso código. Além disso, geraremos automaticamente uma pequena documentação com todos os testes que foram realizados. Aprenderemos a testar códigos que lançam exceções/geram erros, entenderemos o que é o TDD e o PHPUnit (uma ferramenta muito poderosa).

Claro que o curso não te ensinará tudo que você tem a saber sobre testes, mas te dará uma boa iniciação nesse universo. Espero que você tire bastante proveito.

Bons estudos!

Por que testar? - Preparando o ambiente

Nesse momento prepararemos o computador para darmos continuidade ao treinamento. Primeiramente, é necessário ter o PHP instalado, de preferência a versão mais recente. Além disso, utilizaremos o Composer, que já abordamos em treinamentos anteriores.

Com o PHP e o Composer instalados, abriremos o terminal e navegaremos até a pasta do projeto (que deverá ter sido baixado e extraído).

Dentro dela, executaremos o comando composer dump (ou composer dumpautoload, que tem o mesmo efeito). Com o autoload gerado, estaremos prontos para trabalhar. Aproveitaremos, então, para analisar o código do projeo, começando pelo composer.json, no qual temos apenas a configuração do autoloader:

{
    "autoload": {
        "psr-4": {
            "Alura\\Leilao\\": "src/"
        }
    }
}

Na classe Leilao temos a propriedade$descricao, que descreve aquilo que será leiloado e é recebida no construtor. Temos também $lances, que são armazenados em um array por meio da função recebeLance() após a construção da classe. Tais lances podem ser recuperados por meio de getLances().

<?php

namespace Alura\Leilao\Model;

class Leilao
{
    /** @var Lance[] */
    private $lances;
    /** @var string */
    private $descricao;

    public function __construct(string $descricao)
    {
        $this->descricao = $descricao;
        $this->lances = [];
    }

    public function recebeLance(Lance $lance)
    {
        $this->lances[] = $lance;
    }

    /**
     * @return Lance[]
     */
    public function getLances(): array
    {
        return $this->lances;
    }
}

Para a criação de um Lance, é necessário um $usuario, representado por uma classe Usuario cuja única propriedade é $nome, e o $valor do lance.

<?php

namespace Alura\Leilao\Model;

class Lance
{
    /** @var Usuario */
    private $usuario;
    /** @var float */
    private $valor;

    public function __construct(Usuario $usuario, float $valor)
    {
        $this->usuario = $usuario;
        $this->valor = $valor;
    }

    public function getUsuario(): Usuario
    {
        return $this->usuario;
    }

    public function getValor(): float
    {
        return $this->valor;
    }
}
<?php

namespace Alura\Leilao\Model;

class Usuario
{
    /** @var string */
    private $nome;

    public function __construct(string $nome)
    {
        $this->nome = $nome;
    }

    public function getNome(): string
    {
        return $this->nome;
    }
}

Agora que temos o ambiente configurado e entendemos o projeto, vamos começar a desenvolver e entender melhor como funcionam os testes.

Por que testar? - Avaliando um leilão

Agora que já conhecemos o nosso projeto, vamos implementar um avaliador de leilões cuja primeira funcionalidade será buscar o maior valor de lance de um leilão. Para isso, criaremos uma classe Avaliador no namespace "Service". Essa classe terá um método avalia() que receberá um $leilao e não retornará nada (void).

O PhpStorm nos fornece algumas facilidades durante esse processo, como o atalho pubf, que cria automaticamente o esqueleto de um método, além da importação automática da classe Leilao que estamos utilizando. Se a definição do retorno void estiver sublinhada como um erro, basta usarmos "Alt + Enter" e a opção "Switch to PHP 7.1 language level" para indicarmos que queremos usar a versão mais recente do PHP (na qual esse tipo funcionalidade existe).

<?php

namespace Alura\Leilao\Model\Service;
use Alura\Leilao\Model\Leilao;

class Avaliador
{
    public function avalia(Leilao $leilao): void
    {

    }

}

Ainda nessa classe, criaremos uma propriedade $maiorValor para recuperarmos essa informação no futuro. Em seguida, criaremos também o método getMaiorValor(), que retornará um float (afinal estamos trabalhando com valores monetários). No PhpStorm, basta digitarmos get para que a IDE identifique que estamos criando um getter de uma propriedade da classe, montando o seu esqueleto automaticamente.

class Avaliador
{
    private $maiorValor;

    public function avalia(Leilao $leilao): void
    {

    }

    public function getMaiorValor(): float
    {
        return $this->maiorValor;
    }

}

No método avalia, recuperaremos os lances do leilão com $leilao->getLances() e armazenaremos o maior, que é o último lance, na propriedade $maiorValor. Para isso, usaremos a função count() para conseguirmos o números de lances no array e subtrairemos esse valor por 1 para conseguirmos o índice do maior lance.

Continuando, armazenaremos esse retorno em uma variável $ultimoLance e atribuiremos a chamada de $ultimolance->getValor() à nossa propriedade $this->maiorValor.

public function avalia(Leilao $leilao): void
{
    $lances = $leilao->getLances();
    $ultimoLance = $lances[count($lances) - 1];
    $this->maiorValor = $ultimoLance->getValor();
}

Terminada a construção dessa lógica, vamos criar um novo arquivo teste-avaliador na raiz do projeto. Incluiremos nele o arquivo de autoload do Composer e criaremos um Leilao para um "Fiat 147 0KM". Antes de criarmos os lances, precisamos de usuários para esse leilão. Sendo assim, criaremos os usuários $maria e joao, ambos instâncias de Usuario.

<?php

use Alura\Leilao\Model\Leilao;
use Alura\Leilao\Model\Usuario;

require 'vendor/autoload.php';

$leilao = new Leilao('Fiat 147 0km');


$maria = new Usuario('Maria');
$joao = new Usuario('Joao');

Agora podemos iniciar os lances. Faremos isso chamando o método recebeLance() passando uma instância de Leilao() que receberá como argumentos o usuário responsável pelo lance e o valor deste. Teremos no momento dois lances: $joao, 2000 e $maria, 2500.

$leilao = new Leilao('Fiat 147 0km');


$maria = new Usuario('Maria');
$joao = new Usuario('Joao');

$leilao->recebeLance(new \Alura\Leilao\Model\Lance($joao, 2000));
$leilao->recebeLance(new \Alura\Leilao\Model\Lance($maria, 2500));

Chamaremos o nosso avaliador de $leiloeiro, recebendo a instância de Avaliador, e chamaremos o método avalia() passando o nosso $leilao. Feita a avaliação, pegaremos o $maiorValor com $leiloeiro->getMaiorValor() e imprimiremos essa variável com o echo. Já sabemos que o maior valor desse leilão é 2500, portanto nosso código estará correto se esse valor for exibido ao final.

Voltaremos ao terminal e executaremos php teste-avaliador.php. Como retorno, teremos:

2500

Ou seja, tudo funcionou como esperado. Entretanto, repare que nessa situação temos apenas um caso de teste, no qual temos poucos lances e sabemos qual é a saída correta. Mas e se tivéssemos dezenas de lances, vários cenários/códigos para testar e diversas tarefas sendo realizadas nesse processo? Ou mesmo que outra pessoa fosse trabalhar com o nosso projeto e precisasse garantir que tudo está funcionando?

Nessa situação, ao receber um 2500 no console, o usuário não saberia se o teste funcionou corretamente ou falhou, ou se o código está operando como deveria. Pensando nisso, como é que podemos entregar um feedback melhor para quem for executar esse teste? A ideia é termos um código de testes que seja mais informativo, e começaremos esse processo no próximo vídeo.

Sobre o curso PHP e TDD: testes com PHPUnit

O curso PHP e TDD: testes com PHPUnit possui 150 minutos de vídeos, em um total de 58 atividades. Gostou? Conheça nossos outros cursos de PHP em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda PHP acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas