Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Ganhando tempo com Casos de Testes Michael Castillo Granados [email_address] http://dgmike.com.br
Já se sentiu sem saber onde está o erro de sua aplicação? Calma! Isso é mais normal do que parece!
Tenho uma solução para seus problemas! Test-Driven Development
Por que usar? <ul><li>O sistema é percorrido por testes do começo ao fim </li></ul><ul><li>O código do projeto se torna ma...
O que você precisa? Suite de testes estável: Php_Unit SimpleTest Coragem Bom Senso
Escrevendo os primeiros testes <ul><li><?php </li></ul><ul><li>include  ( 'simpletest/autorun.php' ); </li></ul><ul><li>in...
Escrevendo os primeiros testes <ul><li><?php </li></ul><ul><li>include  ( 'simpletest/autorun.php' ); </li></ul><ul><li>in...
Escrevendo os primeiros testes <ul><li><?php </li></ul><ul><li>include ('simpletest/autorun.php'); </li></ul><ul><li>inclu...
Escrevendo os primeiros testes <ul><li><?php </li></ul><ul><li>include ('simpletest/autorun.php'); </li></ul><ul><li>inclu...
Escrevendo os primeiros testes <ul><li><?php </li></ul><ul><li>include ('simpletest/autorun.php'); </li></ul><ul><li>inclu...
O primeiro resultado Fatal error:  Call to undefined function  soma() in  calculadora_test.php  on line 6 Isto acontece po...
Resolvendo o problema <ul><li><?php </li></ul><ul><li>function  soma ($ a , $ b ) { </li></ul><ul><li>return  $ a +$ b ; <...
Resultado <ul><li>OK </li></ul><ul><li>Test cases run: 1/1, Passes: 1, Failures: 0, Exceptions: 0 </li></ul>
Você ainda pode rodar os testes no seu navegador Falha Sucesso
Vamos complicar um pouco? <ul><li>class  CalculadoraTest  extends   UnitTestCase  { </li></ul><ul><li>function  testSoma()...
E o resultado dos testes muda um pouquinho... <ul><li>calculadora_test.php </li></ul><ul><li>1)  Equal expectation fails b...
Métodos que podemos verificar <ul><li>assertTrue($x) </li></ul><ul><li>assertFalse($x) </li></ul><ul><li>assertNull($x) </...
Verificando um erro <ul><li><?php </li></ul><ul><li>include_once ('simpletest/autorun.php'); </li></ul><ul><li>class Comet...
Antes e depois de executar testes <ul><li>Métodos especiais  setUp  e  tearDown </li></ul><ul><li>class  LoggerTest  exten...
Brincando com o banco de dados <ul><li><?php </li></ul><ul><li>class  Db { </li></ul><ul><li>var   $ con, $ res ; </li></u...
E a seguinte tabela do banco Tabela usuario com  primary_key  em  id
Escrevemos o seguinte teste include_once  ( 'simpletest/autorun.php' ); include_once  ( 'db.php' ); include_once  ( 'usuar...
Escrevemos o seguinte teste include_once  ( 'simpletest/autorun.php' ); include_once  ( 'db.php' ); include_once  ( 'usuar...
Escrevemos o seguinte teste include_once ('simpletest/autorun.php'); include_once ('db.php'); include_once ('usuario.php')...
Escrevemos o seguinte teste include_once ('simpletest/autorun.php'); include_once ('db.php'); include_once ('usuario.php')...
Banco de dados sempre é uma dor de cabeça! <ul><li>Alterar registros, verificar se foram alterados em funções que obviamen...
Duck typing: usando mockups <ul><li>Se quacheia como um pato e anda como um pato, então é um pato </li></ul>class  BancoPa...
Testes diferentes para retornos diferentes da função  query class  PatoTest  extends  UnitTestCase { function  setUp() { g...
Testando a Web <ul><li>Sim! É possível testar seus formulários. </li></ul><ul><li>Que tal economizar seus dedos ao preench...
Um exemplo clássico
WebTestCase <?php include_once  ( 'simpletest/web_tester.php' ); class  LoginTest  extends  WebTestCase { function  setUp(...
WebTestCase <?php include_once ('simpletest/web_tester.php'); class LoginTest extends WebTestCase { function setUp() { $db...
Tem que rodar os testes separados? <ul><li><?php </li></ul><ul><li>require_once ( 'simpletest/autorun.php' ); </li></ul><u...
Mas Mike, não é mais lento escrever tanto teste? NÃO!
Então... onde ganho? <ul><li>Na hora de descobrir onde  aquela função de alteração de última hora afeta seu código </li></...
Onde encontrar?
Upcoming SlideShare
Loading in …5
×

Ganhando tempo com casos de testes

4,015 views

Published on

Como usar a biblioteca SimpleTest do PHP para ganhar tempo resolvendo os problemas mas simples do dia-a-dia. Essa apresentação foi elaborada para o PHPConference2008 que aconteceu em Osasco, SP Brasil.

Published in: Technology

Ganhando tempo com casos de testes

  1. 1. Ganhando tempo com Casos de Testes Michael Castillo Granados [email_address] http://dgmike.com.br
  2. 2. Já se sentiu sem saber onde está o erro de sua aplicação? Calma! Isso é mais normal do que parece!
  3. 3. Tenho uma solução para seus problemas! Test-Driven Development
  4. 4. Por que usar? <ul><li>O sistema é percorrido por testes do começo ao fim </li></ul><ul><li>O código do projeto se torna mais confiável </li></ul><ul><li>Ganho de tempo nos projetos </li></ul><ul><li>A equipe pode efetuar testes locais e ao final de um período, executar testes globais verificando se alguém quebrou a programação de outro </li></ul>
  5. 5. O que você precisa? Suite de testes estável: Php_Unit SimpleTest Coragem Bom Senso
  6. 6. Escrevendo os primeiros testes <ul><li><?php </li></ul><ul><li>include ( 'simpletest/autorun.php' ); </li></ul><ul><li>include ( 'calculadora.php' ); </li></ul><ul><li>class CalculadoraTest extends UnitTestCase { </li></ul><ul><li>function testSoma() { </li></ul><ul><li>$ resultado = soma( 5 , 6 ); </li></ul><ul><li>$ this ->assertEqual ($ resultado , 11 ); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  7. 7. Escrevendo os primeiros testes <ul><li><?php </li></ul><ul><li>include ( 'simpletest/autorun.php' ); </li></ul><ul><li>include ( 'calculadora.php' ); </li></ul><ul><li>class CalculadoraTest extends UnitTestCase { </li></ul><ul><li>function testSoma() { </li></ul><ul><li>$resultado = soma(5, 6); </li></ul><ul><li>$this->assertEqual ($resultado, 11); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  8. 8. Escrevendo os primeiros testes <ul><li><?php </li></ul><ul><li>include ('simpletest/autorun.php'); </li></ul><ul><li>include ('calculadora.php'); </li></ul><ul><li>class CalculadoraTest extends UnitTestCase { </li></ul><ul><li>function testSoma() { </li></ul><ul><li>$resultado = soma(5, 6); </li></ul><ul><li>$this->assertEqual ($resultado, 11); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>O módulo de testes deve extender uma classe especial da SimpleTest , neste caso: UnitTestCase
  9. 9. Escrevendo os primeiros testes <ul><li><?php </li></ul><ul><li>include ('simpletest/autorun.php'); </li></ul><ul><li>include ('calculadora.php'); </li></ul><ul><li>class CalculadoraTest extends UnitTestCase { </li></ul><ul><li>function test Soma() { </li></ul><ul><li>$resultado = soma(5, 6); </li></ul><ul><li>$this->assertEqual ($resultado, 11); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>O método deve começar com test
  10. 10. Escrevendo os primeiros testes <ul><li><?php </li></ul><ul><li>include ('simpletest/autorun.php'); </li></ul><ul><li>include ('calculadora.php'); </li></ul><ul><li>class CalculadoraTest extends UnitTestCase { </li></ul><ul><li>function testSoma() { </li></ul><ul><li>$resultado = soma (5, 6); </li></ul><ul><li>$this-> assertEqual ($resultado, 11); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>assertEqual verifica se o resultado é igual ao esperado: 11
  11. 11. O primeiro resultado Fatal error: Call to undefined function soma() in calculadora_test.php on line 6 Isto acontece porque a função soma ainda não existe
  12. 12. Resolvendo o problema <ul><li><?php </li></ul><ul><li>function soma ($ a , $ b ) { </li></ul><ul><li>return $ a +$ b ; </li></ul><ul><li>} </li></ul>Uma forma simples de resolver, nada de resolver coisas a mais
  13. 13. Resultado <ul><li>OK </li></ul><ul><li>Test cases run: 1/1, Passes: 1, Failures: 0, Exceptions: 0 </li></ul>
  14. 14. Você ainda pode rodar os testes no seu navegador Falha Sucesso
  15. 15. Vamos complicar um pouco? <ul><li>class CalculadoraTest extends UnitTestCase { </li></ul><ul><li>function testSoma() { </li></ul><ul><li>$ this ->assertEqual ( soma ( 5 , 6 ), 11 ); </li></ul><ul><li>} </li></ul><ul><li>function testMultiSoma() { </li></ul><ul><li>$ this ->assertEqual ( soma ( 5 , 6 , 4 , 6 , 8 , 9 ), 38 ); </li></ul><ul><li>} </li></ul><ul><li>function testSomaVazio() { </li></ul><ul><li>$ this ->assertEqual( soma (), 0 ); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  16. 16. E o resultado dos testes muda um pouquinho... <ul><li>calculadora_test.php </li></ul><ul><li>1) Equal expectation fails because [ Integer: 11 ] differs from [ Integer: 38 ] by 27 at [F:wwwphpconferenceexemploscalculadora_test.php line 11] </li></ul><ul><li>in testMultiSoma </li></ul><ul><li>in CalculadoraTest </li></ul><ul><li>Exception 1! </li></ul><ul><li>Unexpected PHP error [ Missing argument 1 for soma() , called in F:wwwphpconferenceexemploscalculadora_test.php on line 14 and defined] severity [E_WARNING] in [F:wwwphpconferenceexemploscalculadora.php line 2] </li></ul><ul><li>in testSomaVazio </li></ul><ul><li>in CalculadoraTest </li></ul><ul><li>Exception 2! </li></ul><ul><li>Unexpected PHP error [ Missing argument 2 for soma() , called in F:wwwphpconferenceexemploscalculadora_test.php on line 14 and defined] severity [E_WARNING] in [F:wwwphpconferenceexemploscalculadora.php line 2] </li></ul><ul><li>in testSomaVazio </li></ul><ul><li>in CalculadoraTest </li></ul><ul><li>FAILURES!!! </li></ul><ul><li>Test cases run: 1/1, Passes: 2, Failures: 1, Exceptions: 2 </li></ul>
  17. 17. Métodos que podemos verificar <ul><li>assertTrue($x) </li></ul><ul><li>assertFalse($x) </li></ul><ul><li>assertNull($x) </li></ul><ul><li>assertNotNull($x) </li></ul><ul><li>assertIsA($x, $t) </li></ul><ul><li>assertNotA($x, $t) </li></ul><ul><li>assertEqual($x, $y) </li></ul><ul><li>assertNotEqual($x, $y) </li></ul><ul><li>assertWithinMargin($x, $y, $m) </li></ul><ul><li>assertOutsideMargin($x, $y, $m) </li></ul><ul><li>assertIdentical($x, $y) </li></ul><ul><li>assertNotIdentical($x, $y) </li></ul><ul><li>assertReference($x, $y) </li></ul><ul><li>assertClone($x, $y) </li></ul><ul><li>assertPattern($p, $x) </li></ul><ul><li>assertNoPattern($p, $x) </li></ul><ul><li>expectError($x) </li></ul><ul><li>assert($e) </li></ul>Ao todo, temos 18 métodos de verificação unitária no SimpleTest
  18. 18. Verificando um erro <ul><li><?php </li></ul><ul><li>include_once ('simpletest/autorun.php'); </li></ul><ul><li>class CometendoErros extends UnitTestCase { </li></ul><ul><li>function testEsperandoUmErro() { </li></ul><ul><li>$this-> expectError ( 'Nao foi possivel somar' ); </li></ul><ul><li>soma_impossivel (); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>function soma_impossivel () { </li></ul><ul><li>trigger_error ( 'Nao foi possivel somar' ); </li></ul><ul><li>} </li></ul>
  19. 19. Antes e depois de executar testes <ul><li>Métodos especiais setUp e tearDown </li></ul><ul><li>class LoggerTest extends UnitTestCase { </li></ul><ul><li>function setUp() { @ unlink ( 'registro.log' ); } </li></ul><ul><li>function tearDown() { @ unlink ( 'registro.log' ); } </li></ul><ul><li>function testLogger() { </li></ul><ul><li>$ this ->assert False ( file_exists ( 'registro.log' )); </li></ul><ul><li>logger( 'Mensagem que vai para o log' ); </li></ul><ul><li>$ this ->assert True ( file_exists ( 'registro.log' )); </li></ul><ul><li>$this->assert Equal ( file_get_contents ( 'registro.log' ), “Mensagem que vai para o log. ” ); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  20. 20. Brincando com o banco de dados <ul><li><?php </li></ul><ul><li>class Db { </li></ul><ul><li>var $ con, $ res ; </li></ul><ul><li>function __construct () { </li></ul><ul><li>$ this ->con = new PDO( 'mysql:host=localhost;dbname=phpconference' , </li></ul><ul><li>'phpconference' , 'phpconference' ); </li></ul><ul><li>} </li></ul><ul><li>function query ( $ query ) { </li></ul><ul><li>$ this ->res = $ this ->con->query( $ query ); </li></ul><ul><li>} </li></ul><ul><li>function total( $ table ) { </li></ul><ul><li>$ res = $ this ->con->query( &quot;SELECT COUNT(*) AS t FROM $ table &quot; ); </li></ul><ul><li>return $ res ->fetchObject()->t; </li></ul><ul><li>} </li></ul><ul><li>function clear ( $ table ) { </li></ul><ul><li>$ this ->con->query( &quot;DELETE FROM $ table &quot; ); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>Tomando como base a seguinte classe de manipulação de Banco de dados
  21. 21. E a seguinte tabela do banco Tabela usuario com primary_key em id
  22. 22. Escrevemos o seguinte teste include_once ( 'simpletest/autorun.php' ); include_once ( 'db.php' ); include_once ( 'usuario.php' ); class UsuarioTest extends UnitTestCase { var $ db ; function setUp() { $ this ->db = new Db; $ this ->db->clear( 'usuarios' ); } function testNovoUsuario() { $ usuario = new Usuario(array ( 'nome' => 'Michael' , 'idade' => 24 , 'sexo' => 'masculino' , 'site' => 'http://dgmike.com.br' , )); $ this ->assertEqual( $ this ->db->total( 'usuarios' ), 1 ); } }
  23. 23. Escrevemos o seguinte teste include_once ( 'simpletest/autorun.php' ); include_once ( 'db.php' ); include_once ( 'usuario.php' ); class UsuarioTest extends UnitTestCase { var $db; function setUp() { $this->db = new Db; $this->db->clear('usuarios'); } function testNovoUsuario() { $usuario = new Usuario(array ( 'nome' => 'Michael', 'idade' => 24, 'sexo' => 'masculino', 'site' => 'http://dgmike.com.br', )); $this->assertEqual($this->db->total('usuarios'), 1); } } Incluimos os arquivos: - autorun da simpletest - classe de banco de dados - classe Usuário (que iremos testar)
  24. 24. Escrevemos o seguinte teste include_once ('simpletest/autorun.php'); include_once ('db.php'); include_once ('usuario.php'); class UsuarioTest extends UnitTestCase { var $db; function setUp() { $ this ->db = new Db; $ this ->db->clear( 'usuarios' ); } function testNovoUsuario() { $usuario = new Usuario(array ( 'nome' => 'Michael', 'idade' => 24, 'sexo' => 'masculino', 'site' => 'http://dgmike.com.br', )); $this->assertEqual($this->db->total('usuarios'), 1); } } Ao inicializar, o banco de dados (de testes) é limpo. Podemos inserir também dados de teste caso necessário.
  25. 25. Escrevemos o seguinte teste include_once ('simpletest/autorun.php'); include_once ('db.php'); include_once ('usuario.php'); class UsuarioTest extends UnitTestCase { var $db; function setUp() { $this->db = new Db; $this->db->clear('usuarios'); } function testNovoUsuario() { $ usuario = new Usuario(array ( 'nome' => 'Michael' , 'idade' => 24 , 'sexo' => 'masculino' , 'site' => 'http://dgmike.com.br' , )); $ this ->assertEqual( $ this ->db->total( 'usuarios' ), 1 ); } } Ao usar a classe Usuario nosso banco de dados deve adicionar um registro, logo o total de usuários deve ser 1 .
  26. 26. Banco de dados sempre é uma dor de cabeça! <ul><li>Alterar registros, verificar se foram alterados em funções que obviamente adicionam ao banco de dados, reescrever os testes sobre áreas já testadas. </li></ul><ul><li>Sim, concordo! Trabalhar com banco de dados é uma dor-de-cabeça! Mas nem sempre você precisa se conectar ao banco de dados de verdade </li></ul>
  27. 27. Duck typing: usando mockups <ul><li>Se quacheia como um pato e anda como um pato, então é um pato </li></ul>class BancoPato { function query() {} function numRows() {} } // Gerando o pato Mock :: generate ('BancoPato'); $ banco = new MockBancoPato (); // Setando o retorno do método query do meu // objeto de manipulação de banco de dados Pato $ banco ->setReturnValue( 'query' , true );
  28. 28. Testes diferentes para retornos diferentes da função query class PatoTest extends UnitTestCase { function setUp() { global $banco, $pato; $banco = new MockBancoPato(); $pato = new Pato(); } function testPato() { global $banco, $pato; $banco->setReturnValue( 'query' , true ); $this->assertEqual( 'Voce inseriu um pato com sussesso!' , $pato->insert( array ( 'Rodrigo' ))); } function testPatoInvalido() { global $banco, $pato; $banco->setReturnValue( 'query' , false ); $this->assertEqual( 'Ops! Ocorreram falhas ao tentar adicionar um pato' , $pato->insert( array ( 'Rodrigo' ))); } }
  29. 29. Testando a Web <ul><li>Sim! É possível testar seus formulários. </li></ul><ul><li>Que tal economizar seus dedos ao preencher aquele formulário enorme? </li></ul><ul><li>Verificar resultados de busca </li></ul><ul><li>Verificar se os links o levam para a página correta </li></ul><ul><li>Verificar se o usuário está logado ou não na conta do sistema </li></ul>
  30. 30. Um exemplo clássico
  31. 31. WebTestCase <?php include_once ( 'simpletest/web_tester.php' ); class LoginTest extends WebTestCase { function setUp() { $ db = new Db; $ db ->clear( 'usuarios' ); $ usuario = new Usuario( array ( 'nome' => 'Michael' , 'idade' => 24, 'sexo' => 'masculino' , 'site' => 'http://dgmike.com.br' , )); } function testLoginErrado () { $ this ->get( 'http://localhost/phpconference/exemplos/login.php' ); $ this ->assertTrue($ this ->setField( 'nome' , 'Augusto' )); $ this ->clickSubmit( 'Login' ); // Clicamos no botão submit $ this ->assertText( 'Login Invalido' ); // Verificamos se o texto existe } }
  32. 32. WebTestCase <?php include_once ('simpletest/web_tester.php'); class LoginTest extends WebTestCase { function setUp() { $db = new Db; $db->clear('usuarios'); $usuario = new Usuario(array ( 'nome' => 'Michael', 'idade' => 24, 'sexo' => 'masculino', 'site' => 'http://dgmike.com.br', )); } function testLoginErrado () { $ this ->get( 'http://localhost/phpconference/exemplos/login.php' ); $ this ->assertTrue($ this ->setField( 'nome' , 'Augusto' )); $ this ->clickSubmit( 'Login' ); // Clicamos no botão submit $ this ->assertText( 'Login Invalido' ); // Verificamos se o texto existe } } É aqui que acontece a mágica. Fazemos o script navegar como se fosse o usuário. E nada mais de testar na mão para ver se o formuário está correto.
  33. 33. Tem que rodar os testes separados? <ul><li><?php </li></ul><ul><li>require_once ( 'simpletest/autorun.php' ); </li></ul><ul><li>class FileTestSuite extends TestSuite { </li></ul><ul><li>function FileTestSuite() { </li></ul><ul><li>$this->TestSuite( 'All file tests' ); </li></ul><ul><li>foreach ( glob ( '*.test.php' ) as $file) { </li></ul><ul><li>$this->addTestFile($file); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  34. 34. Mas Mike, não é mais lento escrever tanto teste? NÃO!
  35. 35. Então... onde ganho? <ul><li>Na hora de descobrir onde aquela função de alteração de última hora afeta seu código </li></ul><ul><li>A longo prazo são menos falhas a corrigir </li></ul><ul><li>Tem a certeza que está escrevendo certo </li></ul><ul><li>Passa a escrever menos código desnecessário </li></ul><ul><li>Os testes são automatizados, então não precisam de sua interferência para fazer os testes, mesmo do projeto inteiro </li></ul>
  36. 36. Onde encontrar?

×