Ganhando tempo com casos de testes

  • 3,560 views
Uploaded 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 …

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.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
3,560
On Slideshare
0
From Embeds
0
Number of Embeds
4

Actions

Shares
Downloads
111
Comments
0
Likes
7

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Ganhando tempo com Casos de Testes Michael Castillo Granados [email_address] http://dgmike.com.br
  • 2. Já se sentiu sem saber onde está o erro de sua aplicação? Calma! Isso é mais normal do que parece!
  • 3. Tenho uma solução para seus problemas! Test-Driven Development
  • 4. Por que usar?
    • O sistema é percorrido por testes do começo ao fim
    • O código do projeto se torna mais confiável
    • Ganho de tempo nos projetos
    • 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
  • 5. O que você precisa? Suite de testes estável: Php_Unit SimpleTest Coragem Bom Senso
  • 6. Escrevendo os primeiros testes
    • <?php
    • include ( 'simpletest/autorun.php' );
    • include ( 'calculadora.php' );
    • class CalculadoraTest extends UnitTestCase {
    • function testSoma() {
    • $ resultado = soma( 5 , 6 );
    • $ this ->assertEqual ($ resultado , 11 );
    • }
    • }
  • 7. Escrevendo os primeiros testes
    • <?php
    • include ( 'simpletest/autorun.php' );
    • include ( 'calculadora.php' );
    • class CalculadoraTest extends UnitTestCase {
    • function testSoma() {
    • $resultado = soma(5, 6);
    • $this->assertEqual ($resultado, 11);
    • }
    • }
  • 8. Escrevendo os primeiros testes
    • <?php
    • include ('simpletest/autorun.php');
    • include ('calculadora.php');
    • class CalculadoraTest extends UnitTestCase {
    • function testSoma() {
    • $resultado = soma(5, 6);
    • $this->assertEqual ($resultado, 11);
    • }
    • }
    O módulo de testes deve extender uma classe especial da SimpleTest , neste caso: UnitTestCase
  • 9. Escrevendo os primeiros testes
    • <?php
    • include ('simpletest/autorun.php');
    • include ('calculadora.php');
    • class CalculadoraTest extends UnitTestCase {
    • function test Soma() {
    • $resultado = soma(5, 6);
    • $this->assertEqual ($resultado, 11);
    • }
    • }
    O método deve começar com test
  • 10. Escrevendo os primeiros testes
    • <?php
    • include ('simpletest/autorun.php');
    • include ('calculadora.php');
    • class CalculadoraTest extends UnitTestCase {
    • function testSoma() {
    • $resultado = soma (5, 6);
    • $this-> assertEqual ($resultado, 11);
    • }
    • }
    assertEqual verifica se o resultado é igual ao esperado: 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. Resolvendo o problema
    • <?php
    • function soma ($ a , $ b ) {
    • return $ a +$ b ;
    • }
    Uma forma simples de resolver, nada de resolver coisas a mais
  • 13. Resultado
    • OK
    • Test cases run: 1/1, Passes: 1, Failures: 0, Exceptions: 0
  • 14. Você ainda pode rodar os testes no seu navegador Falha Sucesso
  • 15. Vamos complicar um pouco?
    • class CalculadoraTest extends UnitTestCase {
    • function testSoma() {
    • $ this ->assertEqual ( soma ( 5 , 6 ), 11 );
    • }
    • function testMultiSoma() {
    • $ this ->assertEqual ( soma ( 5 , 6 , 4 , 6 , 8 , 9 ), 38 );
    • }
    • function testSomaVazio() {
    • $ this ->assertEqual( soma (), 0 );
    • }
    • }
  • 16. E o resultado dos testes muda um pouquinho...
    • calculadora_test.php
    • 1) Equal expectation fails because [ Integer: 11 ] differs from [ Integer: 38 ] by 27 at [F:wwwphpconferenceexemploscalculadora_test.php line 11]
    • in testMultiSoma
    • in CalculadoraTest
    • Exception 1!
    • 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]
    • in testSomaVazio
    • in CalculadoraTest
    • Exception 2!
    • 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]
    • in testSomaVazio
    • in CalculadoraTest
    • FAILURES!!!
    • Test cases run: 1/1, Passes: 2, Failures: 1, Exceptions: 2
  • 17. Métodos que podemos verificar
    • assertTrue($x)
    • assertFalse($x)
    • assertNull($x)
    • assertNotNull($x)
    • assertIsA($x, $t)
    • assertNotA($x, $t)
    • assertEqual($x, $y)
    • assertNotEqual($x, $y)
    • assertWithinMargin($x, $y, $m)
    • assertOutsideMargin($x, $y, $m)
    • assertIdentical($x, $y)
    • assertNotIdentical($x, $y)
    • assertReference($x, $y)
    • assertClone($x, $y)
    • assertPattern($p, $x)
    • assertNoPattern($p, $x)
    • expectError($x)
    • assert($e)
    Ao todo, temos 18 métodos de verificação unitária no SimpleTest
  • 18. Verificando um erro
    • <?php
    • include_once ('simpletest/autorun.php');
    • class CometendoErros extends UnitTestCase {
    • function testEsperandoUmErro() {
    • $this-> expectError ( 'Nao foi possivel somar' );
    • soma_impossivel ();
    • }
    • }
    • function soma_impossivel () {
    • trigger_error ( 'Nao foi possivel somar' );
    • }
  • 19. Antes e depois de executar testes
    • Métodos especiais setUp e tearDown
    • class LoggerTest extends UnitTestCase {
    • function setUp() { @ unlink ( 'registro.log' ); }
    • function tearDown() { @ unlink ( 'registro.log' ); }
    • function testLogger() {
    • $ this ->assert False ( file_exists ( 'registro.log' ));
    • logger( 'Mensagem que vai para o log' );
    • $ this ->assert True ( file_exists ( 'registro.log' ));
    • $this->assert Equal ( file_get_contents ( 'registro.log' ), “Mensagem que vai para o log. ” );
    • }
    • }
  • 20. Brincando com o banco de dados
    • <?php
    • class Db {
    • var $ con, $ res ;
    • function __construct () {
    • $ this ->con = new PDO( 'mysql:host=localhost;dbname=phpconference' ,
    • 'phpconference' , 'phpconference' );
    • }
    • function query ( $ query ) {
    • $ this ->res = $ this ->con->query( $ query );
    • }
    • function total( $ table ) {
    • $ res = $ this ->con->query( &quot;SELECT COUNT(*) AS t FROM $ table &quot; );
    • return $ res ->fetchObject()->t;
    • }
    • function clear ( $ table ) {
    • $ this ->con->query( &quot;DELETE FROM $ table &quot; );
    • }
    • }
    Tomando como base a seguinte classe de manipulação de Banco de dados
  • 21. E a seguinte tabela do banco Tabela usuario com primary_key em id
  • 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. 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. 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. 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. Banco de dados sempre é uma dor de cabeça!
    • Alterar registros, verificar se foram alterados em funções que obviamente adicionam ao banco de dados, reescrever os testes sobre áreas já testadas.
    • 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
  • 27. Duck typing: usando mockups
    • Se quacheia como um pato e anda como um pato, então é um pato
    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. 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. Testando a Web
    • Sim! É possível testar seus formulários.
    • Que tal economizar seus dedos ao preencher aquele formulário enorme?
    • Verificar resultados de busca
    • Verificar se os links o levam para a página correta
    • Verificar se o usuário está logado ou não na conta do sistema
  • 30. Um exemplo clássico
  • 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. 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. Tem que rodar os testes separados?
    • <?php
    • require_once ( 'simpletest/autorun.php' );
    • class FileTestSuite extends TestSuite {
    • function FileTestSuite() {
    • $this->TestSuite( 'All file tests' );
    • foreach ( glob ( '*.test.php' ) as $file) {
    • $this->addTestFile($file);
    • }
    • }
    • }
  • 34. Mas Mike, não é mais lento escrever tanto teste? NÃO!
  • 35. Então... onde ganho?
    • Na hora de descobrir onde aquela função de alteração de última hora afeta seu código
    • A longo prazo são menos falhas a corrigir
    • Tem a certeza que está escrevendo certo
    • Passa a escrever menos código desnecessário
    • Os testes são automatizados, então não precisam de sua interferência para fazer os testes, mesmo do projeto inteiro
  • 36. Onde encontrar?