Hy, folks!!!
E ai galera, finalmente vamos fazer um post, mão-na-massa, o que seria isso ???
????????????????????????
Simples um teste em classes, vamos usar agora o PHPunit para fazer um teste que ira funcionar realmente.
O que é Unit Testing?
- Testes para pequenos trechos de código (unidades)
- Verifica se o comportamento de classes e funções é o esperado
- Caso erros são encontrados exceções são lançadas
- Não interfere com o seu código-fonte
- Testes para pequenos trechos de código (unidades)
- Verifica se o comportamento de classes e funções é o esperado
- Caso erros são encontrados exceções são lançadas
- Não interfere com o seu código-fonte
- Os testes são automatizados
- Eles são executados continuamente durante o ciclo de desenvolvimento
- Detectam falhas tanto de digitação e lógica e também comportamentos inesperados
Exemplo
- class Classe1
- {
- public function somar($a, $b)
- {
- return $a+$b;
- }
- public function subtrair($a, $b)
- {
- return $a-$b;
- }
- }
- // Teste da classe
- $foo = new Classe1();
- $soma = $foo->somar(2, 2);
- $subracao = $foo->subtrair(2, 2);
- echo '2 mais 2 = ' . $soma;
- echo '2 menos 2 = ' . $subtracao;
- // Funciona conforme esperado!
Apesar do exemplo simples, ilutra uma prática bem comum: a de inserir vários echo() e print() para confirmar o funcionamento de uma classe ou função.
O PHPUnit é uma framework que tem como objetivo automatizar e padronizar a forma como nosso código é testado.
"Whenever you are tempted to type something into a print statement or a debugger expression, write it as a test instead." -- Martin Fowler
Ou seja: "Toda vez que sentir vontade de escrever um print ou outra expressão de debug, pare e crie um teste!"
- // Especifique o caminho do PHPUnit
- require_once '/usr/share/php/PHPUnit/Framework.php';
- // Especifique o caminho da classe a ser testada
- require_once 'Classe1.php';
- // Como a classe a ser testada se chama "Classe1", a classe de teste deverá se chamar "ClasseTest" e (neste caso) irá herdar de PHPUnit_Framework_TestCase
- class Classe1Test extends PHPUnit_Framework_TestCase
- {
- // Funções de teste devem ter o prefixo "test"
- public function testSoma()
- {
- // A classe a ser testada é instanciada
- $foo = new Classe1();
- // Testamos a afirmação que "4" é o resultado de passar "2" e "2" (ou seja, 2 + 2 = 4)
- $this->assertEquals('4', $foo->somar(2, 2));
- }
- public function testSubtracao()
- {
- // idem (veja função acima)
- $foo = new Classe1();
- $this->assertEquals('0', $foo->subtrair(2, 2));
- }
- }
O resultado:
- PHPUnit 3.3.16 by Sebastian Bergmann.
- .
- Time: 0 seconds
- OK (2 tests, 2 assertions)
- // Funciona conforme esperado!
O que aconteceu?
Criamos uma classe (Classe1Test) de teste para testar a nossa classe (Classe1) e usamos o PHPUnit para testar o funcionamento esperado
Não é mais complicado?
- Sim e não! Inicialmente pode parecer bem mais simples inserir alguns print() ou echo() e verificar manaulmente, mas ao longo prazo usar o PHPUnit traz diversas vantagens:
- Os testes ficam separados do código, assim não corremos o risco de esqueçer testes no meio do código. Devido à separação também não é necessário ficar voltando e comentando e descomentando as linhas de teste inseridas manualmente.
- Para aplicações um pouco mais complexas (por exemplo com várias classes interagindo juntas ou com AJAX) as vezes não é possível colocar echo() ou print() em qualquer lugar. Até mesmo o FirePHP gera erros de 'header'!
- Usando o PHPUnit criamos vários testes e sempre que desejarmos podemos rodá-los novamente para testar modificações.
- E o melhor de tudo, não precisamos fazer nada na hora de colocar a aplicação no ar. Simplesmente não fazemos o upload da pasta de testes! O código-fonte original segue intacto.
Como funciona?
- Crie uma classe de teste para testar uma classe já existente
- Excute os testes no terminal (ou prompt de comando) e veja os resultados
- A melhor maneira da aprender isto é através de exemplos então vamos instalar o PHPUnit e criar alguns testes!
Instalação do PHPUnit
Quem usa o linux pode fazer facilmente:
- # se não tiver o PEAR instalado
- apt-get install pear
- # descubra o canal do PHPUnit
- pear channel-discover pear.phpunit.de
- # instale o phpunit
- pear install phpunit/PHPUnit
- # Ele fica instalado por padrão no /usr/share/php/PHPUnit
- # Agora é só incluir o framework nos arquivos de teste e começar!
Quem usa windows procure no google! Não deve ser muito complicado... (se não me engano ele já vem incluso no pacote XAMPP)
Guia para criar Unit Tests
- Os testes para a classe "Classe1" (Classe1.php) deverão ser localizados dentro da classe "Classe1Test" (Classe1Test.php), sempre use o sufixo "Test" (NomeDaClasseTest)
- Na maioria dos casos a classe de teste irá herdar (extends) da classe PHPUnit_Framework_TestCase
- Os testes deverão ser funções públicas com o prefixo "test" (testSomar, testSubtrair, etc)
- Os testes são baseados em afirmações, ou seja: afirmamos que o resultado esperado da função X é Y, e testamos a afirmação pra ver se ela procede.
- Usamos funções como assertEquals() para testar afirmações (exemplos a seguir)
Algumas Afirmações disponíveis (Funções de Teste)
- Existem dezenas (veja a documentação http://www.phpunit.de/manual/), seguem algumas das mais comuns:
- assertEquals($valor, funcao()) (afirma que o valor retornado da funcao é igual a $valor)
- assertNotEquals($valor, funcao()) (afirma que o valor retornado da funcao não é igual a $valor)
- assertSame($valor, funcao()) (testa se o objeto retornado é igual a $valor)
- assertTrue(funcao()) (afirma que o valor retornado é === true)
- assertFalse(funcao()) (=== false)
- setExpectedException (avisa sobre uma exceção que deverá ser lançada)
Como rodar os testes
Através do terminal (ou prompt de comando), no diretório do arquivo de teste digite:
- phpunit NomeDaClasseTest
- # para rodar os testes contidos no arquivo NomeDaClasseTest.php
Vamos ver alguns exemplos na próxima página.
O test seguinte usa a função assertEquals() para checar o retorno de um método:
- // Especifique o caminho do PHPUnit
- require_once '/usr/share/php/PHPUnit/Framework.php';
- // Especifique o caminho da classe a ser testada
- require_once 'Classe2.php';
- class Classe2Test extends PHPUnit_Framework_TestCase
- {
- public function testCumprimentarSemParametro()
- {
- // O comportamento esperado é que retorne "Olá fulano", testa esta afirmação
- $this->assertEquals('Olá fulano', $foo->cumprimentar());
- }
- public function testCumprimentarComParametro()
- {
- // Instancia a classe e passa "Alex" ao construtor
- $foo = new Classe2('Alex');
- // O comportamento esperado é que retorne "Olá Alex", testa esta afirmação
- $this->assertEquals('Olá Alex', $foo->cumprimentar());
- }
- // Funções de teste também podem ser identificados pela anotação @test no DocBlock
- /**
- * @test
- */
- public function vaiDarErrado()
- {
- // Instancia a classe e passa "ciclano" ao construtor
- $foo = new Classe2('ciclano');
- // O comportamento esperado é que retorne "Olá ciclano", mas vamos afirmar que retornará outro valor para forçar um erro
- $this->assertEquals('Olá Alex', $foo->cumprimentar());
- }
- }
Outro teste simples que retorna o seguinte:
- PHPUnit 3.3.16 by Sebastian Bergmann.
- ..F
- Time: 0 seconds
- There was 1 failure:
- 1) vaiDarErrado(Classe2Test)
- Failed asserting that two strings are equal.
- expected string <Olá Alex>
- difference < xxxx???>
- got string <Olá ciclano>
- /caminho/para/o/arquivo/Classe2Test.php:35
- FAILURES!
- Tests: 3, Assertions: 3, Failures: 1.
Ou seja, quando um teste falha ele informa o arquivo e linha onde ocorreu o erro.
Explica também qual foi o erro:
- O valor esperado era "Ola Alex"
- O valor retornado foi "Ola ciclano"
E ele ainda mostra a diferença ( xxxx???)
Fornecendo valores para os testes
- As vezes não basta só um teste com um valor estático
- Podemos criar uma função para alimentar o teste usando vários valores (e nada impede que sejam de fontes externas)
- A função é identificada através da anotação @dataProvider no DocBlock
Exemplo:
Uma versão um pouco mais complicada para explicar o uso do data provider em testes:
- // Demonstração de "Data Providers"
- class Classe3Test extends PHPUnit_Framework_TestCase
- {
- // Informa o nome do forneçedor de dados (@dataProvider) para a clase de teste
- /**
- * @dataProvider provider
- */
- // Recebe 3 parâmetros
- public function testCombine($a, $b, $c)
- {
- // Afirma que o valor do terceiro parâmetro é igual a concatenação dos primeiros dois separados por um espaço
- $this->assertEquals($c, $a . ' ' . $b);
- }
- // A função fornecedora de valores
- public function provider()
- {
- // retorna um array contendo 3 grupos de valores a serem testados
- return array(
- array('Hello', 'World', 'Hello World'),
- array('É', 'Nois', 'É Nois'),
- array('Deu', 'Errado', 'Deu Certo')
- );
- }
- }
Valor retornado:
- PHPUnit 3.3.16 by Sebastian Bergmann.
- ..F
- Time: 0 seconds
- There was 1 failure:
- 1) testCombine(Classe3Test) with data set #2 ('Deu', 'Errado', 'Deu Certo')
- Failed asserting that two strings are equal.
- expected string <Deu Certo>
- difference < xxxxx?>
- got string <Deu Errado>
- /home/alex/Documents/aw/Articles/PHPUnit/Classe3Test.php:16
- FAILURES!
- Tests: 3, Assertions: 3, Failures: 1.
Resumindo...
- O assunto é bastante extenso e realmente fica difícil cobrir todas as possibilidades (que são quase infinitas)
- É possível criar testes para testar se Exceções são lançadas conforme esperado, para testar classes de acesso ao banco de dados e muito mais
- O ideal seria implementar isto em uma aplicação que esteja desenvolvendo, ou seja, crie uma pasta para os testes e vá criando testes para as suas classes nela
Todo o código-fonte para os exemplos e outros exemplos mais complexos (todos bem documentados) estão disponíveis:
Espero que tenham gostado e que eu tenha introduzido bem este assunto que é frequentemente subestimado e importantíssimo quande se trata de desenvolvimento.
Este post, foi melhorado para uma linguagem mais visual e facíl de entender =D...
Fonte PHPbr