Testes Unitários ============ Uma vez que o framework de testes do Yii é construído em cima do [PHPUnit](http://www.phpunit.de/), é recomendado que você primeiro consulte [sua documentação](http://www.phpunit.de/manual/current/en/index.html) para entender o básico sobre como escrever um teste unitário. Nós resumimos a seguir os princípios básicos de escrita de um teste unitário no Yii: * Um teste unitário é escrito em termos de uma classe `XyzTest` que estende de [CTestCase] ou [CDbTestCase], onde `Xyz` representa a classe sendo testada. Por exemplo, para testar a classe `Post`, por convenção devemos chamar a classe de teste unitário correspondente de `PostTest`. A classe-mãe [CTestCase] é destinada para testes unitários genéricos, enquanto a [CDbTestCase] é adequada para testar classes de modelo [active record](/doc/guide/database.ar). Já que `PHPUnit_Framework_TestCase` é a classe-mãe de ambas as classes, nós podemos usar todos os métodos herdados desta classe. * A classe de teste unitário é salva em um arquivo PHP chamado de `XyzTest.php`. Por convenção, o arquivo de teste unitário pode ser armazenado no diretório `protected/tests/unit`. * A classe de teste contém na maior parte um conjunto de métodos de teste chamados como `testAbc`, onde `Abc` geralmente é o nome do método da classe que será testado. * Um método de teste geralmente contém uma série de métodos de asserção (por exemplo, `assertTrue`, `assertEquals`) que servem como checkpoints ao validar o comportamento da classe alvo. A seguir, descrevemos principalmente como escrever testes unitários para classes de modelo [active record](/doc/guide/database.ar). Estenderemos as nossas classes de [CDbTestCase] porque ela fornece o suporte às fixtures de banco de dados que introduzimos na seção anterior. Suponha que queremos testar a classe do modelo `Comment` (comentário) no [exemplo de blog](http://www.yiiframework.com/demos/blog/). Começamos criando uma classe chamada de `CommentTest` e a salvando como `protected/tests/unit/CommentTest.php`: ~~~ [php] class CommentTest extends CDbTestCase { public $fixtures=array( 'posts'=>'Post', 'comments'=>'Comment', ); ...... } ~~~ Nesta classe, especificamos o atributo `fixtures` como um array que especifica quais fixtures serão usadas por este teste. O array representa um mapeamento dos nomes das fixtures aos nomes das classes de modelo ou aos nomes das tabelas das fixtures (por exemplo, do nome de fixture `posts` para a classe de modelo `Post`). Note que ao mapear para nomes de tabelas de fixtures, devemos prefixar o nome da tabela com dois pontos (por exemplo, `:Post`) para diferenciá-lo dos nomes de classe de modelo. E ao usar nomes de classes de modelo, as tabelas correspondentes serão consideradas como tabelas de fixtures. Conforme descrevemos anteriormente, as tabelas das fixtures serão resetadas a algum estado conhecido toda vez que um método de teste for executado. Os nomes das fixtures nos permitem acessar os seus dados nos métodos de teste de uma maneira conveniente. O código a seguir demonstra a sua típica utilização: ~~~ [php] // retorna todas as linhas na tabela da fixture 'Comment' $comments = $this->comments; // retorna a linha cujo alias é 'sample1' na tabela da fixture `Post` $post = $this->posts['sample1']; // retorna a instância de AR representando a linha de dados 'sample1' $post = $this->posts('sample1'); ~~~ > Note|Nota: Se uma fixture for declarada usando seu nome de tabela (por exemplo, `'posts'=>':Post'`), então o terceiro uso acima não é válido porque nós não temos informações sobre com qual classe de modelo a tabela está associada. Em seguida, escrevemos o método `testApprove` para testar o método `approve` na classe de modelo `Comment`. O código é bastante claro: primeiro inserimos um comentário de status pendente; então verificamos que este comentário está em status pendente retornando ele do banco de dados; e finalmente chamamos o método `approve` e verificamos se o status mudou conforme o esperado. ~~~ [php] public function testApprove() { // insere um comentário de status pendente $comment=new Comment; $comment->setAttributes(array( 'content'=>'comment 1', 'status'=>Comment::STATUS_PENDING, 'createTime'=>time(), 'author'=>'me', 'email'=>'me@example.com', 'postId'=>$this->posts['sample1']['id'], ),false); $this->assertTrue($comment->save(false)); // verifica se o comentário está em status pendente $comment=Comment::model()->findByPk($comment->id); $this->assertTrue($comment instanceof Comment); $this->assertEquals(Comment::STATUS_PENDING,$comment->status); // chama approve() e verifica se o comentário tem o status aprovado $comment->approve(); $this->assertEquals(Comment::STATUS_APPROVED,$comment->status); $comment=Comment::model()->findByPk($comment->id); $this->assertEquals(Comment::STATUS_APPROVED,$comment->status); } ~~~