Aloha! Primeiramente, obrigado ao pessoal pelas belas palavras
de incentivo e tudo mais: é esse tipo de coisa que nos empolga pra
continuar trabalhando e estudando duro.
No primeiro artigo sobre SimpleTest, criamos um caso de teste completo de uma calculadora. Relembrando nossa telinha bonita do caso de teste?
Agora vejamos – e se, por exemplo, tivéssemos não apenas uma calculadora
em nossa aplicação, mas também uma agenda de compromissos, uma agenda
de contatos, um wiki, um mural de recados e – enfim, se nossa aplicação fosse composta por N classes, como faríamos para rodar os casos de teste unitários de TODAS AS CLASSES?
Na
TDD, como vimos antes, escrevemos todos os testes antes de começarmos a
implementar nossa aplicação em si: quando pensamos “rodar os testes”,
isso se aplica a todas as classes e funcionalidades que possam gerar
erros em nossa aplicação.
Aí você: “Rapaz, vou ter que acessar teste por teste como fiz com a calculadora? Mamãe, eu tenho 253 casos de uso!!!!”
Imagina só se você executar, URL por URL, ou comando por comando, 253 casos de uso. =/
Pensando nisso, a SimpleTest disponibiliza um recurso de agrupamento de casos de teste chamado de Test Suite.
Esse recurso permite agrupar vários casos de testes numa só classe,
facilitando e permitindo a execução desses testes com uma só chamada.
Seria como um script de checagem, onde cada item seria um caso de teste:
Checagem do carro
- Checar Óleo
- Checar Rodas
- Checar Água Carburador
- Checar itens de segurança
A test suite funciona exatamente assim, executando cada caso de teste
na ordem que você desejar: o “check list” roda e no final você tem
todas as falhas que ocorreram, separadas por caso de teste e método.
Codando!
Bom, vamos supor que vamos ter uma aplicação composta por 5 classes:
ClasseA, ClasseB, ClasseC, ClasseD e ClasseE. Cada uma delas tem suas
próprias implementações e vamos ter que fazer casos de testes que
testem elas individualmente.
Para ilustrar o funcionamento, vamos escrever um método para todas as classes chamado Dizer:
esse método deverá receber a uma string e retornar “Estou dizendo ”
concatenado com o que você passou como parâmetro. Exemplificando
$obj->Dizer('Muito Bacana'); // Estou Dizendo Muito Bacana
Vamos botar esse método em todas as classes apenas para simularmos as passagens e não passagens de teste delas. hehhehe
Bom,
partindo do pressuposto que você esteja com o SimpleTest instalado e
com nossa estrutura de arquivos do artigo de iniciação a ele, vamos
escrever o caso de teste da ClasseA que será salvo dentro da nossa
pasta tests e terá o nome de classe_a_test.php.
require_once('simpletest/autorun.php');
require_once('../classes/classe_a.php');
class TestOfClasseA extends UnitTestCase {
function testDizer() {
$classea = new ClasseA();
$this->assertIdentical($classea->dizer('Muito Bacana'), 'Estou dizendo Muito Bacana');
}
}
Relembrando um pouco:
- Fazemos o include do arquito autorun.php para automatizar nossos testes;
- Fazemos o include da classe que vai ser testada;
- Implementamos a classe de teste iniciando por “Test” a fim de que a SimpleTest execute-a automaticamente;
- Criamos o método testDizer para testar o método dizer da nossa ClasseA;
- Fazemos um assertIdentical
que executará nosso método dizer passando “Muito Bacana” e esperará
como resultado algo IDÊNTICO a “Estou dizendo Muito Bacana”;
Beleza, agora vamos rodar nosso teste …
Como era esperado (espero), nosso teste deu pau porque não
escrevemos nossa ClasseA ainda em arquivo algum. Então, vamos
escrevê-la e salvá-la dentro da pasta classes com o nome de classe_a.php:
class ClasseA {
function dizer($frase) {
return 'Estou dizendo ' . $frase;
}
}
Agora, vamos rodar novamente nosso teste:
Massa demais! Fizemos novamente um caso de teste. Até aí nenhuma novidade.
Agora o exercício braçal: crie os casos de teste para a ClasseB. ClasseC, ClasseD e ClasseE lembrando que:
- Classes da aplicação devem ser salvas dentro da pasta classes
- Classes dos casos de teste dentro da pasta tests
Após a criação delas, faça os testes (jura?) e veja se está tudo ok.
Criando nossa suite de testes
Agora que executamos todos os testes de forma separada, vamos juntá-los em nossa suite para fazê-los todos de uma vez só.
Vamos criar nossa suite de testes no arquivo all_tests.php e salvá-la na pasta tests junto com todos os nosses casos de uso.
require_once('simpletest/autorun.php');
require_once('classe_a_test.php');
require_once('classe_b_test.php');
require_once('classe_c_test.php');
require_once('classe_d_test.php');
require_once('classe_e_test.php');
class AllTests extends TestSuite {
function AllTests() {
$this->TestSuite('All tests');
$this->addTestCase(new TestOfClasseA());
$this->addTestCase(new TestOfClasseB());
$this->addTestCase(new TestOfClasseC());
$this->addTestCase(new TestOfClasseD());
$this->addTestCase(new TestOfClasseE());
}
}
Explicando nosso script:
- fazemos o include de simpletest/autorun.php para fazer rodar nossos testes
- fazemos os includes de todas os casos de testes que usaremos na suite
- criamos uma classe AllTests que extende TestSuite, que por sua vez é a classe que será responsável pelo agrupamento e execução de todos os testes
- criamos um método AllTests que fará a execução dos casos de teste
- nomeamos a suite de testes com o nome All tests com o método $this->TestSuite;
- Adicionamos
então todos os nossos casos de teste com o método
$this->addTestCase, instanciando o objeto de cada classe de teste
Agora, basta rodar:
Pronto!
Nossa suite agrupou nossos testes (que eram cinco ao todo, cada um com
um método de teste) e executou todos de uma vez. A lógica da suíte é
você inserir os testes conforme seu contexto e sua necessidade de
agrupamento de testes. Para incluir, basta repetir o procedimento já
feito no arquivo da suíte:
- faça o require_once do arquivo php do caso de teste
- inclua o caso de teste com $this->addTestCase
E se algum teste falha-se? Vamos fazer o teste da
ClasseB falhar. Para isso altere a classe B para para retornar algo que
não seja “Estou dizendo” mas sim “Eu vou dizer “: com isso, nosso
teste vai falhar. Após alterar a classeB, rode a suite de testes
novamente:
Como
pode ser visto, nossa suite de testes dá o erro exetamente onde ele
aconteceu: no nosso caso, a suite de testes que chamamos de All tests
reportou o erro do caso de teste TestOfClasseB no método testDizer.
Maneirasso, não?
Nossa suite mostra todas as falhas por caso de teste. Simples e rápido.
E vamos às considerações
A forma como fizemos a construção da nossa suite de testes está diferente da forma como o próprio site da SimpleTest (http://www.simpletest.org/en/start-testing.html) mostra em sua página inicial no Quick Start, que está diferente do link que deveria ser a mesma explicação mais detalhada, mas não é. Se olharmos o script de test suite do quick start, aplicando ao nosso exemplo, teríamos:
require_once('simpletest/autorun.php');
class AllTests extends TestSuite {
function AllTests() {
$this->TestSuite('All tests');
$this->addFile('classe_a_test.php');
... outros casos de teste ...
}
}
Com certeza é um jeito mais prático: ao invés de fazermos os
includes dos casos de testes e fazermos os instanciamentos dos mesmos
no addTestCase, requerendo mais programação, simplesmente podemos
incluir o teste com um addFile. E isso realmente funciona.
Mas infelizmente não sem algumas adaptações no código.
Se
quiser reescrever sua suite de testes nesse formato, se atente ao fato
que o SimpleTest aparentemente trabalha com a suite de testes acessando
os caminhos absolutos dos arquivos e se perde quando referenciamos
nossos arquivos, mesmo que eles estejam na mesma pasta tests. Para
contornar isso, coloque a inclusão do arquivo de classe no caso de
testes e a referência ao arquivo do caso de teste na suite com seus
caminhos absolutos. Vamos isso na classeA por exemplo:
Na classe_a_test.php teríamos:
require_once($_SERVER['DOCUMENT_ROOT'] . '/app_tdd/classes/classe_a.php');
E na nossa suite all_tests.php seria re-escrita como:
require_once('simpletest/autorun.php');
class AllTests extends TestSuite {
function AllTests() {
$this->TestSuite('All tests');
$this->addFile($_SERVER['DOCUMENT_ROOT'] . '/app_tdd/tests/classe_a_test.php');
}
}
Espero que tenham gostado! No próximo artigo falaremos um pouco sobre MockObjetcs.
Até lá.