Back-End

19 fev, 2019

PHPUnit no Laravel – Parte 01

Publicidade

O PHPUnit é um dos mais antigos e conhecidos pacotes de testes unitários para PHP. Ele é projetado principalmente para testes unitários, o que significa testar seu código nos menores componentes possíveis, mas também é incrivelmente flexível e pode ser usado para muito mais do que apenas testes unitários.

O PHPUnit inclui muitas asserções simples e flexíveis que permitem testar facilmente seu código, o que funciona muito bem quando você está testando componentes específicos. Isso significa, no entanto, que testar códigos mais avançados, como controladores e validação de submissão de formulários, pode ser muito mais complicado.

Para ajudar a tornar as coisas mais fáceis para os desenvolvedores, o framework PHP Laravel inclui uma coleção de ajudantes de teste de aplicativos, que permitem escrever testes PHPUnit muito simples para testar partes complexas do seu aplicativo.

O objetivo deste artigo é apresentar os fundamentos do teste PHPUnit usando as asserções PHPUnit padrão e os auxiliares de teste do Laravel.

O objetivo é que você aprenda a escrever testes básicos para suas aplicações até o final do artigo.

Pré-requisitos

Este artigo presume que você já esteja familiarizado com o Laravel e saiba como executar comandos dentro do diretório do aplicativo (como comandos do php artisan).

Criaremos algumas classes de exemplo básicas para aprender como funcionam as diferentes ferramentas de teste e, como tal, é recomendável criar um novo aplicativo.

Se tiver o instalador do Laravel configurado, você poderá criar um novo aplicativo de teste executando:

laravel new introducao-phpunit

Como alternativa, você pode criar um novo aplicativo usando o Composer diretamente:

composer create-project laravel/laravel introducao-phpunit

Outras opções de instalação também podem ser encontradas na documentação do Laravel.

Criando um novo teste

O primeiro passo ao usar o PHPUnit é criar uma nova classe de teste. A convenção para as classes de teste é que elas são armazenadas em ./tests/ no diretório do aplicativo. Dentro dessa pasta, cada classe de teste é nomeada com o final Test.php“. Este formato permite que o PHPUnit encontre cada classe de teste – ela irá ignorar qualquer coisa que não termine em Test.php.

Em uma nova aplicação Laravel, você notará dois arquivos no diretório ./tests/: ExampleTest.php e TestCase.php. O arquivo TestCase.php é um arquivo de bootstrap para configurar o ambiente do Laravel em nossos testes. Isso nos permite usar Facades Laravel em testes e fornece a estrutura para os auxiliares de teste, que veremos em breve.

O ExampleTest.php é uma classe de teste de exemplo que inclui um caso de teste básico, usando os auxiliares de teste de aplicativo – ignore-o por enquanto.

Para criar uma nova classe de teste, podemos criar um novo arquivo manualmente – ou executar o útil comando make: test do Artisan fornecido pelo Laravel.

Para criar uma classe de teste chamada MeuPrimeiroTest, precisamos apenas executar este comando artisan:

php artisan make:test MeuPrimeiroTest

O Laravel criará uma classe de teste básica, parecida com isso:

<?php
class MeuPrimeiroTest extends TestCase
{
    /**
* A basic test example.
*
* @return void
*/
    public function testExample()
    {
        $this->assertTrue(true);
    }
}

A coisa mais importante a notar aqui é o prefixo test no nome do método. Como o sufixo Test para nomes de classes, este prefixo test diz ao PHPUnit quais métodos devem ser executados durante o teste. Se você esquecer o prefixo test, o PHPUnit irá ignorar o método.

Antes de executarmos o nosso conjunto de testes pela primeira vez, vale a pena destacar o arquivo phpunit.xml padrão que o Laravel fornece.

O PHPUnit procurará automaticamente um arquivo chamado phpunit.xml ou phpunit.xml.dist no diretório atual quando for executado. É aqui que você configura as opções específicas para seus testes.

Há muita informação dentro deste arquivo, entretanto, a seção mais importante, por enquanto, é a definição do diretório testsuite:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit ... >
    <testsuites>
        <testsuite name="Application Test Suite">
            <directory>./tests/</directory>
        </testsuite>
    </testsuites>
    ...
</phpunit>

Isso diz ao PHPUnit para executar os testes que encontra no diretório ./tests/, que como aprendemos anteriormente, é a convenção para armazenar testes.

Agora que criamos um teste básico e estamos cientes da configuração do PHPUnit, é hora de executar nossos testes pela primeira vez.

Você pode executar seus testes PHPUnit executando o comando phpunit:

./vendor/bin/phpunit

Você deve ver algo semelhante a isso como a saída:

PHPUnit 4.8.19 by Sebastian Bergmann and contributors.
..
Time: 103 ms, Memory: 12.75Mb
OK (2 tests, 3 assertions)

Agora que temos uma configuração PHPUnit em funcionamento, é hora de começar a escrever um teste básico.

Note que ele conta dois testes e três asserções, porque o arquivo ExampleTest.php inclui um teste com duas asserções. Nossa classe MeuPrimeiroTest inclui uma única afirmação aprovada.

Escrevendo um teste básico

Para ajudar a cobrir as asserções básicas que o PHPUnit fornece, primeiro criamos uma classe básica que fornece algumas funcionalidades simples.

Crie um novo arquivo no seu diretório ./app/ chamado Caixa.php e copie essa classe de exemplo:

<?php
namespace App;
class Caixa
{
    /**
* @var array
*/
    protected $items = [];
    /**
* Constrói a caixa com os items recebidos
*
* @param array $items
*/
    public function __construct($items = [])
    {
        $this->items = $items;
    }
    /**
* Verifica se um item específico está na caixa
*
* @param string $item
* @return bool
*/
    public function contem($item)
    {
        return in_array($item, $this->items);
    }
    /**
* Remove um item da caixa
*
* @return string
*/
    public function pegarUm()
    {
        return array_shift($this->items);
    }
    /**
* Remove todos os itens que começam com uma determinada letra de dentro da caixa.
*
* @param string $letra
* @return array
*/
    public function comecaCom($letra)
    {
        return array_filter($this->items, function ($item) use ($letra) {
            return stripos($item, $letra) === 0;
        });
    }
}

Em seguida, abra sua classe ./tests/MeuPrimeiroTest.php (que criamos anteriormente) e remova o método testExample que foi criado por padrão. Você deve ficar com uma classe vazia.

Vamos agora usar sete das asserções básicas do PHPUnit para escrever testes para nossa classe Box. Essas afirmações são:

  • assertTrue()
  • assertFalse()
  • assertEquals()
  • assertNull()
  • assertContains()
  • assertCount()
  • assertEmpty()
  • assertTrue() and assertFalse()

assertTrue() e assertFalse() permitem afirmar que um valor é igual a verdadeiro ou falso. Isso significa que eles são perfeitos para testar métodos que retornam valores booleanos.

Em nossa classe Caixa, temos um método chamado contem($item), que retorna true ou false quando o item especificado está na caixa ou não.

Para escrever um teste para isso no PHPUnit, podemos fazer o seguinte:

<?php
use App\Caixa;
class MeuPrimeiroTest extends TestCase
{
    public function testCaixaContemItem()
    {
        $caixa = new Caixa(['carro', 'mochila', 'garfo']);
        $this->assertTrue($caixa->contem('mochila'));
        $this->assertFalse($caixa->contem('cubo magico'));
    }
}

Observe como passamos apenas um único parâmetro nos métodos assertTrue() e assertFalse(), que é a saída do método contem($item).

Se você executar o comando ./vendor/bin/phpunit agora, você perceberá que a saída conclui:

OK (2 tests, 4 assertions)

Isso significa que nossos testes foram aprovados.

Se você trocar o assertFalse() por assertTrue() e executar o comando phpunit novamente, a saída ficará assim:

PHPUnit 4.8.19 by Sebastian Bergmann and contributors.

F.

Time: 93 ms, Memory: 13.00Mb

There was 1 failure:

1) MeuPrimeiroTest::testCaixaContemItem
Failed asserting that false is true.
.
/tests/MeuPrimeiroTest.php:12

FAILURES!
Tests: 2, Assertions: 4, Failures: 1.

Isso nos diz que a afirmação na linha 12 falhou ao afirmar que um valor falso era verdadeiro – quando trocamos o assertFalse() por assertTrue().

Troque de volta e execute novamente o PHPUnit. Os testes devem passar novamente, pois corrigimos o teste quebrado.

assertEquals() and assertNull()

Em seguida veremos assertEquals() e assertNull().

assertEquals() é usado para comparar o valor real da variável com o valor esperado. Queremos usá-lo para verificar se o valor da função pegarUm() é um item que existe atualmente na caixa. Como o método pegarUm() retorna um valor nulo quando a caixa está vazia, podemos usar assertNull() para verificar isso também.

Ao contrário de assertTrue(), assertFalse() e assertNull(), assertEquals() aceita dois parâmetros. O primeiro é o valor esperado e o segundo é o valor real.

Podemos implementar essas asserções em nossa classe da seguinte forma:

<?php
use App\Caixa;

class MeuPrimeiroTest extends TestCase
{
    public function testCaixaContemItem()
    {
        $caixa = new Caixa(['carro', 'mochila', 'garfo']);
        $this->assertTrue($caixa->contem('mochila'));
        $this->assertFalse($caixa->contem('cubo magico'));
    }

    public function testCaixaContemUmItem()
    {
        $caixa = new Caixa(['lençol']);
        $this->assertEquals('lençol', $caixa->pegarUm());
        // Null, agora a caixa está vazia
        $this->assertNull($caixa->pegarUm());
    }
}

Execute o comando phpunit e você deverá ver:

OK (3 tests, 6 assertions)

assertContains(), assertCount(), and assertEmpty()

Finalmente, temos três asserções que funcionam com arrays, que podemos usar para verificar o método comecaCom($letra) em nossa classe Caixa. assertContains() afirma que um valor esperado existe dentro da matriz fornecida, assertCount() afirma que o número de itens na matriz corresponde à quantidade especificada, e assertEmpty() afirma que a matriz fornecida está vazia.

Podemos implementar testes para isso assim:

<?php
use App\Caixa;

class MeuPrimeiroTest extends TestCase
{
    public function testCaixaContemItem()
    {
        $caixa = new Caixa(['carro', 'mochila', 'garfo']);

        $this->assertTrue($caixa->contem('mochila'));
        $this->assertFalse($caixa->contem('cubo magico'));
    }

    public function testCaixaContemUmItem()
    {
        $caixa = new Caixa(['lençol']);

        $this->assertEquals('lençol', $caixa->pegarUm());

        // Null, agora a caixa está vazia
        $this->assertNull($caixa->pegarUm());
    }

    public function testComecaComLetra()
    {
        $caixa = new Caixa(['cooler', 'mouse', 'fone', 'celular', 'computador']);

        $results = $caixa->comecaCom('c');

        $this->assertCount(3, $results);
        $this->assertContains('cooler', $results);
        $this->assertContains('celular', $results);
        $this->assertContains('computador', $results);

        // Vai devolver um array vazio
        $this->assertEmpty($caixa->comecaCom('s'));
    }


}

Salve e execute seus testes novamente:

OK (4 tests, 9 assertions)

Parabéns, você acabou de testar totalmente a classe Caixa usando sete das asserções básicas do PHPUnit. Você pode fazer muito com essas asserções, e a maioria das outras asserções mais complexas disponíveis ainda seguem o mesmo padrão de uso.

Essa é a primeira parte do artigo de TDD no Laravel. Em breve trarei a segunda parte, com testes integrados.

Pratique agora mesmo, instale e configure uma aplicação Laravel e reproduza o artigo acima. Se encontrar alguma dificuldade ou dúvida, deixe nos comentários!