0
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

3,655

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

Transcript of "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?
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×