PHPUnit
O PHPUnit é uma ferramenta de testes de unidade que disponibiliza um ecossistema necessário para realizar testes de forma automatizada em PHP. O PHPUnit está disponível para aplicações com o PHP a partir da versão 5.5.
Ele é instalado como uma dependência ao projeto e se adéqua com a estrutura do mesmo. Possui uma CLI (Interface de Linha de Comando) própria com opções de personalização para a forma de executar os testes.
O PHPUnit é baseado na ideia que o desenvolvedor deve encontrar erros no código-fonte o mais rápido possível. Semelhante a outros frameworks de teste unitário, ele usa assertions para verificar se o código-fonte está se comportando como o esperado.
Também suporta a declaração de dependências explícitas entre métodos de teste. Tais dependências não definem a ordem em que os métodos de teste devem ser executados, mas permitem o retorno de uma instância do ambiente do teste por um produtor e a passagem dele para os consumidores dependentes.
Para executar os testes com o PHPUnit, deve-se chamar o comando phpunit
que estará dentro de ./vendor/bin/phpunit
e referenciar o arquivo phpunit.xml
com as configurações que serão utilizados para a execução dos testes.
O Magento 2 por padrão já possui um arquivo phpunit.xml
que pode ser utilizado, ele se encontra no caminho ./dev/tests/unit/phpunit.xml.dist
. O terceiro argumento passado no comando para a execução de testes será o caminho do módulo.
./vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist app/code/{Vendor}/{Module}
./vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist vendor/{vendor}/{module}
phpunit.xml
Caso seja necessário personalizar a execução de testes (exemplo: ignorar a pasta API do módulo) é possível criar um arquivo phpunit.xml
no próprio módulo e configurar para que os testes sejam executados de acordo com a configuração deste arquivo.
./vendor/bin/phpunit -c app/code/{Vendor}/{Module}/phpunit.xml.dist app/code/{Vendor}/{Module}
./vendor/bin/phpunit -c vendor/{vendor}/{module}/phpunit.xml.dist vendor/{vendor}/{module}
Código base para a implantação
Para escrever testes com o PHPUnit no Magento 2 basta criar a estrutura de pastas \{Vendor}\{Module}\Test\Unit\{ClassDirectory}\{ClassName}Test
estender a classe que \PHPUnit\Framework\TestCase
. O PHPUnit localiza os métodos de teste pelo prefixo test
no nome do método, e neste contém asserções para validar que o método retorne um valor real equivalente ao esperado.
Classe a ser testada:
<?php
namespace {Vendor}\{Module}\{ClassDirectory};
class {ClassName}
{
public function {methodName}(): {type}
{
// Code here
}
}
Classe de teste:
<?php
namespace {Vendor}\{Module}\Test\Unit\{ClassDirectory};
use PHPUnit\Framework\TestCase;
class {ClassName}Test extends TestCase
{
public function test{MethodName}(): {type}
{
// Code here
}
}
Asserções
Asserções são métodos desenvolvidos pelo PHPUnit para assegurar que o valor de um teste é um valor esperado, ou seja, sãos métodos que executam a unidade e certificam que o resultado gerado no teste é o esperado com sucesso ou falham.
Os métodos da classe \PHPUnit\Framework\TestCase
que começam com o prefixo assert, são parte importante dos casos de teste e avaliam se certas condições, decisivas para determinar o sucesso ou falha do teste, geram um resultado esperado.
<?php
namespace {Vendor}\{Module}\Test\Unit\{ClassDirectory};
use PHPUnit\Framework\TestCase;
class {ClassName}Test extends TestCase
{
public function test{MethodName}(): {type}
{
// Code here
$this->assert{Name}({condition});
}
}
É possível verificar a documentação com todas as asserções fornecidas pelo PHPUnit no link “Asserções do PHPUnit“.
Exceções
Usando o método expectException()
, o PHPUnit verifica se durante a exceção do teste é lançada uma exceção dentro do código testado. Além do método expectException()
os métodos expectExceptionCode()
, expectExceptionMessage()
e expectExceptionMessageRegExp()
existem para configurar expectativas de exceções lançadas pelo código sob teste.
<?php
namespace {Vendor}\{Module}\Test\Unit\{ClassDirectory};
use PHPUnit\Framework\TestCase;
class {ClassName}Test extends TestCase
{
public function test{MethodName}(): {type}
{
$this->expectException(\Exception::class);
// Code here
}
}
Provedor de Dados
Com um método provedor de dados (data provider) o PHPUnit permite que o um método de teste seja executado em diferentes cenários, ou seja, consiste em preparar os dados de entradas para que o teste seja executado diversas vezes com dados diferentes.
Um método provedor de dados deve ser do tipo public
, possuir a anotação @dataProvider
como o nome do método e retornar um array de arrays. Cada item do array de retorno, o método de teste chamara como argumento.
<?php
namespace {Vendor}\{Module}\Test\Unit\{ClassDirectory};
use PHPUnit\Framework\TestCase;
class {ClassName}Test extends TestCase
{
/**
* @dataProvider {dataProviderName}
*/
public function test{MethodName}({type} $data): {type}
{
// Code to test here
}
public function {dataProviderName}(): array
{
// Code to provide different input data
return [
[$data1],
[$data2],
[$data3],
...
[$dataN]
];
}
}
Métodos setUp e tearDown
O PHPUnit suporta compartilhamento do código de configuração. Os métodos-modelo setUp()
e tearDown()
são executados uma vez para cada método de teste (e em novas instâncias) da classe do caso de teste. Ambos os métodos devem ser do tipo protected
e não possuir nenhum dado de retorno (void
).
Antes que um método seja executado, um método modelo chamado setUp()
é invocado. O método setUp()
é onde os objetos que serão alvo dos testes são criados.
Uma vez que o método de teste tenha terminado sua execução, seja bem-sucedido ou falho, outro método modelo é invocado tearDown()
. O método tearDown()
é onde os objetos que foram alvo dos testes são limpos, normalmente, implementa-se o método tearDown()
ao alocar recursos externos como arquivos ou sockets no setUp()
.
<?php
namespace {Vendor}\{Module}\Test\Unit\{ClassDirectory};
use PHPUnit\Framework\TestCase;
class {ClassName}Test extends TestCase
{
protected function setUp(): void
{
// Code to set up test objects
}
protected function tearDown(): void
{
// Code to tear down test object
}
public function test{MethodName}(): {type}
{
// Code to test here
}
}
Dublê de Testes
É possível verificar a documentação com tudo sobre os dublês de testes do PHPUnit no link “Dublês de Testes do PHPUnit“.
Os métodos createMock($type)
e getMockBuilder($type)
fornecidos pelo PHPUnit podem ser usados em um teste para gerar automaticamente um objeto que possa atuar como um dublê de teste para a classe original especificada. Esse objeto de dublê de teste pode ser usado em cada contexto onde um objeto da classe original é esperado ou requerido.
$this->createMock({Class}::class)
: este método retorna um objeto de dublê de teste para o tipo especificado (interface ou classe). A criação desse dublê de teste é realizada usando os padrões de boas práticas (os métodos __construct()
e __clone()
da classe original não são executados) e os argumentos passados para um método do dublê de teste não serão clonados.
$this->getMockBuilder({Class}::class)
: este método serve para customizar a geração do dublê de teste usando uma interface fluente. Por padrão, todos os métodos da classe original são substituídos com uma implementação simulada que apenas retorna null
(sem chamar o método original). É possível configurar essas implementações simuladas para retornar um valor quando chamadas.
-
setMethods(array $methods)
: pode ser chamado no objetogetMockBuilder()
para especificar os métodos que devem ser substituídos com um dublê de teste configurável. O comportamento dos outros métodos não muda. Se você chamarsetMethods(null)
, então nenhum dos métodos serão substituídos (utilizado até a versão 7.3.X do PHP); -
onlyMethods(array $methods)
: pode ser chamado no objetogetMockBuilder()
para especificar os métodos que devem ser substituídos por um dublê de teste configurável. O comportamento dos outros métodos não muda. Cada método deve existir na classe que está sendo criada como dublê de teste (utilizado a partir da versão 7.4.X do PHP); -
addMethods(array $methods)
: pode ser chamado no objetogetMockBuilder()
para especificar os métodos que não existem (ainda) na classe de dublê de teste. O comportamento dos outros métodos permanece o mesmo (utilizado a partir da versão 7.4.X do PHP); -
setConstructorArgs(array $args)
: pode ser chamado para fornecer um vetor de parâmetros que é passado ao construtor da classe original (que por padrão não é substituído com uma implementação falsa); -
setMockClassName($name)
: pode ser usado para especificar um nome de classe para a classe de dublê de teste gerada; -
disableOriginalConstructor()
: pode ser usado para desabilitar a chamada ao construtor da classe original; -
disableOriginalClone()
: pode ser usado para desabilitar a chamada ao construtor clone da classe original; -
disableAutoload()
: pode ser usado para desabilitar o__autoload()
durante a geração da classe de dublê de teste.
$this->method('{methodName}')
: o método method('{methodName}')
recebe o nome do método que será testado na classe é tera um retorno void
.
$this->method('{methodName}')->willReturn('{valueToReturn}')
: o método method('{methodName}')
recebe o nome do método que será testado na classe. O método willReturn('{valueToReturn}')
retorna um valor simples para corresponder ao teste, esta sintaxe é o mesmo que $this->method('{methodName}')->will($this->returnValue($value))
.
$this->method('{methodName}')->returnSelf()
: este método retorna o próprio objeto de dublê de teste.
$objectMock->expects($this->once())->method('{methodName}')->with($this->equalTo('something'))
: verifica se um método foi chamado, e com quais argumentos foi chamado, os métodos expects()
e with()
são para especificar como essa interação deve se parecer.
O método with()
pode receber qualquer número de argumentos, correspondendo ao número de argumentos sendo falsos. É possível especificar restrições mais avançadas do que uma simples igualdade no argumento do método.