Testes
=======

Testes são um processo indispensável do desenvolvimento de software. Estando
conscientes disso ou não, nós conduzimos testes o tempo todo enquanto
desenvolvemos uma aplicação Web. Por exemplo, quando escrevemos uma classe em
PHP, podemos usar algum comando `echo` ou `die` para mostrar que implementamos
um método corretamente; quando implementamos uma página da Web contendo um
formulário HTML complexo, nós podemos tentar digitar alguns dados de teste para
termos certeza de que a página interage conosco da maneira esperada.
Desenvolvedores mais avançados escreveriam algum código para automatizar esse
processo de testes de modo que toda vez que precisarmos testar alguma coisa,
só precisamos chamar o código e deixar que o computador realize os testes por
nós. Isso é conhecido como *testes automatizados*, que é o assunto principal
deste capítulo.

O suporte a testes fornecido pelo Yii inclui *testes unitários* e 
*testes funcionais*.

Um teste unitário verifica que uma única unidade de código está funcionando
conforme o esperado. Na programação orientada a objetos, a unidade de código
mais básica é uma classe. Desta forma, um teste unitário precisa principalmente
verificar que cada um dos métodos da interface da classe funcionam
adequadamente. Ou seja, dados diferentes parâmetros de entrada, o teste verifica
se o método retorna os resultados esperados. Testes unitários geralmente são
desenvolvidos pelas pessoas que escrevem as classes sendo testadas.

Um teste funcional verifica que uma funcionalidade (por exemplo, gerenciamento
de posts em um sistema de blog) está funcionando conforme o esperado. Comparado
com um teste unitário, um teste funcional está em um nível superior, porque
uma funcionalidade sendo testada frequentemente envolve múltiplas classes. 
Testes funcionais geralmente são desenvolvidos por pessoas que conhecem muito
bem os requisitos do sistema (elas poderiam ser tanto desenvolvedores quanto
engenheiros de qualidade).


Desenvolvimento Orientado a Testes
-----------------------

A seguir mostramos os ciclos de desenvolvimento no assim chamado 
[desenvolvimento orientado a testes (TDD)](http://en.wikipedia.org/wiki/Test-driven_development):

 1. Crie um novo teste que cubra uma funcionalidade que será implementada.
    Espera-se que o teste falhe em sua primeira execução, porque a
    funcionalidade ainda precisa ser implementada.
 2. Rode todos os testes e certifique-se de que o novo teste falha.
 3. Escreva código para fazer o novo teste passar.
 4. Rode todos os testes e certifique-se de que todos passam.
 5. Refatore o código que foi recém-escrito e certifique-se de que todos os
    testes ainda passam.

Repita os passos de 1 a 5 para avançar na implementação de funcionalidades.


Configuração do Ambiente de Teste
----------------------

Os testes suportados fornecidos pelo Yii requerem 
[PHPUnit](http://www.phpunit.de/) 3.5+ e
[Selenium Remote Control](http://seleniumhq.org/projects/remote-control/) 1.0+.
Por favor, consulte as suas documentações sobre como instalar o PHPUnit e o
Selenium Remote Control.

Quando usamos o comando de console `yiic webapp` para criar uma nova aplicação
Yii, ele gerará automaticamente os seguintes arquivos e diretórios para nós,
para escrevermos e realizarmos novos testes:

~~~
testdrive/
   protected/                contendo arquivos da aplicação protegidos
      tests/                 contendo testes para a aplicação
         fixtures/           contendo fixtures do banco de dados
         functional/         contendo testes funcionais
         unit/               contendo testes unitários
         report/             contendo relatórios de cobertura
         bootstrap.php       o script executado logo no início
         phpunit.xml         o arquivo de configuração do PHPUnit
         WebTestCase.php     a classe base para testes funcionais baseados na Web
~~~

Conforme mostrado acima, nosso código de testes será posto principalmente em
três diretórios: `fixtures`, `functional` e `unit`, e o diretório `report` será
usado para armazenar os relatórios de cobertura do código gerados.

Para executar os testes (sejam testes unitários ou funcionais), podemos executar
os seguintes comandos na janela do console:

~~~
% cd testdrive/protected/tests
% phpunit functional/PostTest.php    // executa um teste individual
% phpunit --verbose functional       // executa todos os testes em 'functional'
% phpunit --coverage-html ./report unit
~~~

O último dos comandos acima executará todos os testes que estão no diretório
`unit` e gerará um relatório de cobertura de código no diretório `report`.
Note que a [extensão xdebug](http://www.xdebug.org/) precisa estar instalada e
ativa para gerar relatórios de cobertura de código.


Script de Inicialização dos Testes
--------------------

Vamos observar o que deve haver no arquivo `bootstrap.php`. Este arquivo é tão
especial porque ele é como o [script de entrada](/doc/guide/basics.entry) e
é o ponto de partida quando executamos um conjunto de testes.

~~~
[php]
$yiit='path/to/yii/framework/yiit.php';
$config=dirname(__FILE__).'/../config/test.php';
require_once($yiit);
require_once(dirname(__FILE__).'/WebTestCase.php');
Yii::createWebApplication($config);
~~~

No código acima, primeiro incluímos o arquivo `yiit.php` do framework Yii, que
inicializa algumas constantes globais e inclui todas as classes-mãe de teste
necessárias. Então criamos uma instância da aplicação Web usando o arquivo de
configuração `test.php`. Se checarmos o `test.php`, descobriremos que ele herda
do arquivo de configuração `main.php` e adiciona um componente de aplicação
`fixture` cuja classe é [CDbFixtureManager]. Nós descreveremos as fixtures em
dealhes na próxima seção.

~~~
[php]
return CMap::mergeArray(
	require(dirname(__FILE__).'/main.php'),
	array(
		'components'=>array(
			'fixture'=>array(
				'class'=>'system.test.CDbFixtureManager',
			),
			/* descomente o seguinte para prover uma conexão com o banco de dados de teste
			'db'=>array(
				'connectionString'=>'DSN do banco de dados de teste',
			),
			*/
		),
	)
);
~~~

Quando rodamos testes que envolvem o banco de dados, devemos fornecer um banco
de dados de teste, de modo que a execução do teste não interfira com as
atividades normais do desenvolvimento ou da produção. Para fazê-lo, só
precisamos descomentar a configuração `db` no trecho acima e preencher a
propriedade `connectionString` com o DSN (nome da fonte de dados) do banco de
dados de testes.

Com esse script de inicialização, quando rodamos os testes unitários, teremos
uma instância da aplicação que é aproximadamente a mesma que responde às
requisições Web. A diferença principal é que ela tem o gerenciador de fixtures
e está usando o banco de dados de testes.


<div class="revision">$Id$</div>
