[vc_row][vc_column][vc_column_text]Atenção! Este post é de Junho de 2013, muitas coisas evoluíram desde então, procure aqui no blog mesmo por conteúdos mais atualizados.
A um bom tempo que venho bolando praticar TDD fora do framework que utilizo, o CakePHP. Dias atrás "brinquei" um pouquinho e percebi que realizar testes fora do ambiente do framework é mais simples do que eu imaginava, aqui vai um pequeno exemplo de como você também pode fazer para iniciar desenvolver com orienteação a testes.
Do que precisamos?
- PHP >= 5.3.*
- PHPUnit
- Xdebug
Os exemplos foram todos codados em ambiente Linux (Debian 7) utilizando a IDE Netbeans.
Primeiramente você deve instalar o PHP, espero que pelo menos isso você já tenha em sua máquina, não me envergonhe... Em seguida o PHPUnit que não vou fornecer o procedimento de instalação por ser muito simples e está muito bem documentado em português inclusive no site oficial
www.phpunit.de e por último o xdebug pra gente gerar o coverage de nossos testes. O coverage é opcional mas é uma ferramenta excelente para que você possa analisar qual o percentual de seu código está coberto por testes além de um ótimo debugger para o PHP. Para instalar o xdebug no Linux Debian-like basta um comando
#apt-get install php5-xdebug, já para Windows siga os passos descritos na página oficial
www.xdebug.org.
Iniciando
Primeiramente crie um arquivo em PHP, sugiro por meios didáticos que o nome seja
UserTest.php. Nele, logo no início informamos que precisamos do PHPUnit, com isso basta dar um require em
PHPUnit/Autoload.php.
Após isto crie uma classe chamada
User, apenas a crie e deixe-a vazia. Feito isto é hora de criar a classe de testes, nomeie-a como
UserTest e extenda-a da classe
PHPUnit_Framework_TestCase conforme a imagem abaixo.

Agora vamos instanciar a classe
User em nossa classe de teste a partir do método
setUp que é executado automaticamente quando executado o PHPUnit.

Aí já temos um começo... faltam alguns passos, mas são muito simples, fica calmo.
Abra o terminal do seu Sistema Operacional, no meu caso
Konsole por utilizar Debian com KDE, entre na pasta onde encontra-se seu projeto de teste e, com o PHPUnit instalado corretamente você pode o executar simplesmente digitando $
phpunit NomeDaClasseDeTestes isto fará todos os testes existentes nela seja executados. Em nosso caso ainda não existem testes o que nos retornará uma falha indicando da falta de testes na classe.
Dica: para que a visualização dos resultados dos testes se torne mais intuitiva podemos habilitar cores adicionado o parâmetro
--colors antes do nome da classe de teste. Em nosso caso a execução correta do teste seria $
phpunit --colors UserTest

Agora que já sabemos que teremos de criar um teste ao menos, vamos o fazer. Não sei se é algo realmente necessário mas eu sempre gosto de testar se a classe instanciada é a esperada, com isso crio um método nomeando-o como
testInstanceOf, isto é, sempre que se tratar de um teste o nome do método deve iniciar com a palavra
test em minúsculo seguido da descrição desejada em camelCased. Agora ao digitar no terminal
$ phpunit --colors UserTest haverá um teste que passará, olha só...

Note que acima foi apenas um simples teste e este normalmente passará, a não ser que você faça-o quebrar propositalmente. Então para de fato levarmos o TDD em sua correta implementação (vermelho, verde, refatora) devemos criar um teste que quebre, faremos o mesmo abaixo .

Perceba que setamos um nome e depois demos um assertEquals do nome esperado (à esquerda) com o nome retornado (à direita).
Dica: Leia os assertions do PHPUnit para conhecer as possibilidades, visto que não é o intuito deste post abranger nada além da asserção de equivalência.
https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.assertions.
Agora lembre-se de que chamamos o método
setName e em seguida o
getName, porém ambos não existem ainda. Isto fará o teste quebrar, mas esta não é a única forma de quebra de teste, outra forma é, o método existindo porém não comportando-se conforme o esperado. Ao executar
$ phpunit --colors UserTest há inúmeras linhas de erro, erros estes que corrigiremos a seguir.

Na classe
User (não na
UserTest) criaremos uma variável privada
$name e seu
getter e
setter. Agora ao executarmos
$ phpunit --colors UserTest o teste simplesmete ficará verde, olha só que legal!!!

Isto porque tanto o método
setName quanto o
getName da classe testada comportaram-se conforme o esperado.
Vamos fazer mais um teste quebrar? Que tal gerar uma senha aleatória para o usuário, seguindo um exemplo de um formulário de recuperação de senha onde uma senha provisória é enviada ao email do solicitante.
Criamos o teste primeiro (conforme as boas práticas do TDD sugerem: primeiro o teste e em seguida o código "definitivo"). Desta vez assertaremos a NÃO equivalênia, ou seja, testaremos se a senha retornada não é nula. Neste exemplo utilizaremos um recurso bastante útil do PHPUnit que é uma mensagem de informação a respeito do erro, definimos como
"Empty Password" com isso ao teste quebrar a gente poderá ver além de qual teste é, uma mensagem mais amigável a respeito do erro. Execute o comando
$ phpunit --colors UserTest e veja mais um teste quebrar.

Agora vamos à programação que não só fará o teste passar mas sim como sua aplicação se comportará. Desta vez o teste passa e você tem a certeza de que qualquer alteração futura no método
newPassword da classe
User ao alterar sua lógica será rapidamente visualizado se houveram erros e onde foram para imediata correção.

[/vc_column_text][us_cta title="Interesse em TDD?" title_size="h3" color="custom" bg_color="#422b72" text_color="#ffffff" btn_link="url:https%3A%2F%2Ftddcomphp.com.br||target:%20_blank|" btn_label="Conheça meu livro" btn_size="20px" btn_style="4"]
Então meu livro é perfeito pra você!
Pra ficar melhor ainda, tenho um cupom de 15% de desconto. Clique em "Conheça meu livro" e pegue o seu![/us_cta][vc_column_text]
Coverage
Com o xdebug instalado temos um ótimo
debugger e unindo-o ao PHPUnit podemos visualizar quanto de nosso código está coberto por testes, isto veremos agora. Primeiramente esclareço que somente podemos gerar o code
coverage se a classe de testes estiver separada da classe que está sendo testada então crie um novo arquivo chamado
User.php, copie toda a classe
User que atualmente encontra-se no arquivo
UserTest.php e cole-o no arquivo recém criado.

Agora inclua o arquivo
User.php no
UserTest.php. Como neste exemplo não estamos seguindo o padrão PSR-0, não há auto loader com isso vamos no
require_one() mesmo.

Ok, aparentemente está tudo ok, se rodarmos o phpunit com as classes em arquivos separados todos os testes devem passar assim como já passaram anteriormente. Novamente o comando
$ phpunit --colors UserTest.

Legal, agora que em arquivos separados todos os testes permaneceram funcionando basta que geramos o code coverage dos mesmos, para isto o phpunit nos oferece diversas formas de saída para que possamos analisar, pode ser um xml, html, php ou um txt. Utilizaremos o formato html.
Digitando o comando
$ phpunit --colors --coverage-html coverage UserTest temos
- phpunit - o próprio framework de testes
- --colors - saída com coloração para melhor
- --coverage-html - o formato que será a saída gerada
- coverage - pasta de destino para os arquivos hml
- UserTest - a classe de testes.
Note na imagem abaixo que ao rodar o comando especificando o coverage cria-se um diretório chamado coverage conforme definimos e dentro dele diversos arquivos, era exatamente isto que desejávamos.

Agora entrando no browser na pasta do projeto em que estamos realizando nossos testes é necessário entrar na pasta /coveage. Ao entrar o resultado será como abaixo.

Neste exemplo temos apenas 1 classe testada, caso tivéssemos mais, as mesmas também seriam listadas como na imagem acima. Para visualizar detalhes da cobertura por testes basta que se clique no arquivo desejado.

O mais legal de tudo é que no próprio coverage você encontra informações para suas dúvidas como a coloração das linhas e abrangência do teste.
Este foi um post muito breve do que vem a ser trabalhar com desenvolvimento orientado a testes mas como o intuito é: ser uma porta de entrada para o TDD em PHP acredito ser válido até mesmo porque muita gente acha que é um bicho de 7 cabeças criar testes. Não, criar testes como pode ser visto ao longo do post é uma tarefa muito simples, o grande problema é: O QUE TESTAR?
Espero ter contribuído de alguma forma, até a próxima ;)
Código-fonte (PHP)
Código-fonte (Ruby)
[/vc_column_text][us_cta title="Interesse em TDD?" title_size="h3" color="custom" bg_color="#422b72" text_color="#ffffff" btn_link="url:https%3A%2F%2Ftddcomphp.com.br||target:%20_blank|" btn_label="Conheça meu livro" btn_size="20px" btn_style="4"]
Então meu livro é perfeito pra você!
Pra ficar melhor ainda, tenho um cupom de 15% de desconto. Clique em "Conheça meu livro" e pegue o seu![/us_cta][/vc_column][/vc_row]