Capítulo 3. Instalando PHPUnit

PHPUnit 3,5 requer PHP 5.2.7 (ou posterior), mas o PHP 5.3.2 (ou posterior) é altamente recomendado. Ele deve ser instalado usando o instalador pear. Este instalador é a espinha dorsal do PEAR, que provê um sistema de distribuição de pacotes PHP, e é fornecido com cada versão do PHP desde a versão 4.3.0.

O canal PEAR ( pear.phpunit.de ) que é usado para distribuir o PHPUnit precisa ser registrado no ambiente PEAR local. Furthermore, a component that PHPUnit depends upon is hosted on the Symfony Components PEAR channel ( pear.symfony-project.com ). Além disso, um componente que o PHPUnit depende está hospedado no canal de componentes de PEAR do Symfony ( pear.symfony-project.com ).

pear channel-discover pear.phpunit.de

pear channel-discover pear.symfony-project.com

Os comandos acima devem ser feitos apenas uma vez (mas se por acaso você adicionar este mais de uma vez não haverá problemas). Agora o instalador PEAR pode ser usado para instalar os pacotes do canal PHPUnit:

pear install phpunit/PHPUnit

Após a instalação você pode encontrar os arquivos de código fonte do PHPUnit dentro do seu diretório PEAR local, o caminho é geralmente /usr/lib/php/PHPUnit.

Apesar do instalador PEAR ser a única forma de apoio para instalar o PHPUnit, você pode instalar o PHPUnit manualmente. Para a instalação manual, faça o seguinte:

1. Download do arquivo de release de http://pear.phpunit.de/get/ e extraí-o para um diretório que é listado no include_path do seu arquivo de configuração php.ini.
2. Prepare o phpunit script:
a. Renomeie o script phpunit.php para phpunit.
b. Substitua o @php_bin@ string nele com o caminho para o intérprete de linha de comando do PHP (normalmente /usr/bin/php).
c. Copie-o para um diretório que está no seu caminho e o torne executável (chmod +x phpunit).
3. Prepare o script PHPUnit/Util/PHP.php:
a. Substitua o @php_bin@ string nele com o caminho para o intérprete de linha de comando do PHP (normalmente /usr/bin/php ).

Capítulo 2. Objetivos do PHPUnit

Até agora, temos dois testes para o array do PHP e a função sizeof(). Quando começarmos a testar as numerosas funções array_*() que o PHP oferece, teremos de escrever um teste para cada uma delas. Poderíamos escrever a infra-estrutura para todos esses testes a partir do zero.  No entanto, é muito melhor escrever a infra-estrutura de teste de inicio e, em seguida, escrever apenas as partes de cada teste. PHPUnit é essa infra-estrutura.

Um framework como o PHPUnit tem de resolver um conjunto de restrições, algumas das quais parecem estar sempre em conflito uns com os outros. Simultaneamente, os testes devem ser:

Fácil de aprender a se escrever
Se os testes não são fáceis de escrever, os desenvolvedores não escrevê-los.

Fácil de ler.
Código de teste não deve conter nenhum código extra para que o resultado do teste não fique comprometido com este código.

Fácil de executar.

Os testes devem funcionar com o toque de um botão e apresentar seus resultados em uma forma clara e inequívoca.

Rápida de executar.

Testes devem ser executado de modo que eles possam ser executados rapidamente centenas ou milhares de vezes por dia.

Isolado.
Os testes não devem afetar um ao outro. Se a ordem em que os testes são executados mudar, os resultados dos testes não deve mudar.

Combináveis.
Devemos ser capazes de executar qualquer número ou a combinação dos testes em conjunto. Este a natureza do isolamento (o motivo do isolamento dá razão ao combinável).

Há dois confrontos entre estas restrições:

Fácil de aprender a se escrever versus fácil de escrever.
Testes em geral, não exigem toda a flexibilidade de uma linguagem de programação. Muitas ferramentas de teste dispõe linguagem própria, que inclui apenas as características mínimas necessárias para escrever os testes. Os testes resultantes são fáceis de ler e escrever porque eles não têm nenhum ruído para distraí-lo do conteúdo das provas. No entanto, o aprendizado de ainda outra linguagem de programação e um conjunto de ferramentas de programação é inconveniente e confunde o pensamento.

Isolada versus rápido para executar.
Se você quer que os resultados de um teste não tenha qualquer efeito sobre os resultados de outro, cada teste deve criar o ambiente antes de começar a executar e devolver o ambiente ao seu estado original quando ele terminar. Contudo, a criação do ambiente pode levar um longo tempo: por exemplo, se conectar a um banco de dados e inicializa-lo a um estado conhecido, utilizando dados realistas.

PHPUnit tentativas de resolver esses conflitos usando PHP como linguagem de teste. Sometimes the full power of PHP is overkill for writing little straight-line tests, but by using PHP we leverage all the experience and tools programmers already have in place. Às vezes, todo o poder do PHP é overkill para escrever testes linha reta pouco, mas usando PHP Aproveitamos toda a experiência e os programadores de ferramentas já existentes. Since we are trying to convince reluctant testers, lowering the barrier to writing those initial tests is particularly important. Uma vez que estamos a tentar convencer os testadores relutante, abaixando a barreira de escrever os testes iniciais é particularmente importante.

PHPUnit errs on the side of isolation over quick execution. PHPUnit erra no lado de isolamento durante a execução rápida. Isolated tests are valuable because they provide high-quality feedback. Isolado testes são importantes porque fornecem feedback de alta qualidade. You do not get a report with a bunch of test failures, which were really caused because one test at the beginning of the suite failed and left the world messed up for the rest of the tests. Você não receberá um relatório com um monte de falhas nos testes, que foram realmente causadas por um teste no início da suite falhou e deixou o mundo confuso para o resto dos testes. This orientation towards isolated tests encourages designs with a large number of simple objects. Esta orientação para os testes isolados incentiva projetos com um grande número de objetos simples. Each object can be tested quickly in isolation. Cada objeto pode ser rapidamente testados isoladamente. The result is better designs and faster tests. O resultado é melhor os projetos e os testes mais rápidos.

PHPUnit assume que a maioria dos testes é bem-sucedido e não vale a pena relatar a detalhes de testes bem sucedidos. Quando um teste falha, esse fato é digno de nota e relatórios. A grande maioria dos testes deveriam ser bem sucedidos e não vale a pena comentar sobre eles a não ser para contar o número de testes que foram executados. Esta é uma suposição que realmente está construída nas classes de relatório e não no núcleo do PHPUnit. Quando os resultados de um teste são relatados, você vê qwuantos testes foram executados, mas você só ver os detalhes daqueles que falharam.

Os testes devem ser finos (bem pequenos), testar um aspecto de um objeto. Assim, a primeira vez que um teste falhar, a execução do teste pára, e PHPUnit relata a falha. É uma arte testar vários pequenos testes. Testes bem pequenos melhoram o design geral do sistema.

Quando você testar um objeto com PHPUnit, faça apenas através da interface pública do objeto. Teste baseado apenas no comportamento publicamente visível incentiva você a enfrentar e resolver problemas difíceis de design mais cedo, antes dos resultados da má concepção infectar grande parte do sistema.

Capítulo 1. Automatizar testes

Mesmo bons programadores cometem erros. A diferença entre um bom programador e um programador ruim é que o bom programador utiliza testes para detectar seus erros o mais rapidamente possível. Quanto mais cedo você testar maior a sua chance de encontrar um erro e menos custará para e corrigir. Isso explica por que deixar para tester até pouco antes de lançar o software é tão problemático. A maioria dos erros nem são pegos, e o custo de corrigir os que você captura é tão grande que você tem que realizar uma triagem, porque você simplesmente não pode se dar ao luxo de corrigir todos eles.

Teste com PHPUnit não é uma atividade totalmente diferente do que você já deve estar fazendo, é apenas uma maneira diferente de fazê-lo. A diferença está entre o "testar", ou seja, verificar se o seu programa se comporta como esperado, e realizar uma "bateria de testes", fragmentos executáveis de código que automaticamente testam a veracidade das partes, estes fragmentos de código executável são chamados de testes de unidade.

Neste capítulo, iremos partir de simples "print em tela" para um teste completamente automatizado. Imagine que fomos chamados para fezer testes com o array embutido do PHP. Uma funcionalidade para testar é a função count(). Para um array recém-criado, esperamos que a função count() retorne 0 (zero). Depois que adicionar um elemento, count() deve retornar 1 (um). Exemplo 1.1 mostra o que queremos testar.


Exemplo 1.1: operações com matrizes de teste
$fixture = array ( ) ;
// $fixture is expected to be empty.

$fixture [ ] = 'element' ;
// $fixture is expected to contain one element.
?>


Uma maneira simples de verificar se realmente estamos obtendo os resultados que esperamos é imprimir o resultado de count() antes e após a adição do elemento (ver Exemplo 1.2 ). Se conseguirmos 0 e 1 , array e count() se comportam como esperado.


Exemplo 1.2: imprimir usando para testar as operações de matriz
$fixture = array ( ) ;
print count ( $fixture ) . "\n" ;

$fixture [ ] = 'element' ;
print count ( $fixture ) . "\n" ;
?>


Agora, gostaríamos de avançar a partir de testes que exigem interpretação técnica de testes que podem ser executadas automaticamente. No Exemplo 1.3 , nós escrevemos a comparação dos valores reais e esperados que o código de teste imprimo "ok" se os valores são iguais. Se algum dia vier um "não ok" como mensagem, sabemos que algo está errado.


Exemplo 1.3: Comparando os valores previstos e reais para testar as operações de matriz
$fixture = array ( ) ;
print count ( $fixture ) == 0 ? "ok\n" : "não ok\n" ;

$fixture [ ] = 'element' ;
print count ( $fixture ) == 1 ? "ok\n" : "não ok\n" ;
?>


Abaixo temos agora o fator de comparação de reais e os valores esperados para uma função que gera uma exceção quando há uma discrepância ( Exemplo 1,4 ). Isso nos dá duas vantagens: a escrita de testes se torna mais fácil e nós só temos saída quando algo está errado.


Exemplo 1.4: Usando uma função para testar a afirmação de operações com matrizes
$fixture = array ( ) ;
assertTrue ( count ( $fixture ) == 0 ) ;

$fixture [ ] = 'element' ;
assertTrue ( count ( $fixture ) == 1 ) ;

function assertTrue ( $condition )
{
   if ( ! $condition ) {
      throw new Exception ( 'Assertion failed.' ) ;
   }
}
?>


O teste agora é totalmente automatizada. Ao invés de apenas testar como fizemos com a nossa primeira versão, com esta versão, temos um teste automatizado.

O objetivo do uso de testes automatizados é cometer menos erros. Embora seu código ainda não será perfeito, mesmo com testes excelentes, você provavelmente vai ver uma redução drástica nos defeitos asssim que você começar a automatizar seus testes. Os testes automáticos lhe dão justificativa de confiança em seu código. Você pode usar essa confiança para dar mais saltos ousados no design (Refactoring), se dar melhor com seus colegas (Cross-Team Tests), melhorar as relações com seus clientes, e ir para casa todas as noites com a prova de que o sistema está melhor agora do que Foi esta manhã por causa de seus esforços.