Test Driven Development with PHP

Cezar Junior de Souza
E-mail: cezar08@unochapeco.edu.br
Quem sou eu
●

●

Desenvolvedor PHP há 4 anos;
Bacharel em Sistemas de Informação pela
Unochapecó;

●

Especialista em Eng...
Quem sou eu
●

Tem experiência com:
–

Zend Framework 1;

–

Zend Framework 2;

–

Ruby on Rails 3.2;

–

Dojo;

–

ExtJs;...
O que vamos ver
●

Introdução
–
–

Ciclo

–

Por que devemos testar?

–

Por que não testamos?

–

Testes automatizados

–...
O que vamos ver
●

PHPUnit
–

O que é?

–

Objetivos

–

Instalação

–

Asserções
●
●
●
●
●
●
●

–

assertEquals
assertFal...
O que vamos ver
●

PHPUnit
–

Escrevendo Testes com PHPUnit
●
●
●

Dependência de testes
Provedores de dados
Testando Exce...
O que vamos ver
●

Exemplos
–

Exemplo 1: Conta Bancária

–

Exemplo 2: Carrinho de compras

–

Exemplo 3: Nota fiscal

Mo...
Introdução
●

O que é TDD?
–

É uma das práticas de desenvolvimento de software
sugeridas por diversas metodologias.

–

P...
Introdução
●

O que é TDD?
–

É desenvolvido organicamente, com o feedback do
código executável exibido entre as decisões....
Introdução
●

O que é o TDD?
–

A prática nos ajuda a escrever um software melhor,
com mais qualidade, e um código melhor,...
Introdução

“Toda prática que ajuda a aumentar a qualidade
do software produzido deve ser
estudada.”(Aniche, 2012)
Ciclo
Escrever o teste->Teste Falha->Escreve o programa->Teste passa->Refatora
Por que devemos testar?
●

●

É necessária somente uma resposta para esta pergunta,
para ter a certeza que o nosso código ...
Por que devemos testar?
●

Os Estados Unidos estimam que bugs de software lhes
custam aproximadamente 60 bilhões de dólare...
Por que devemos testar?
●

Um erro de software pode matar pessoas
–

o foguete Ariane 5 explodiu por um erro de software;
...
Por que não testamos?
●

●

●

Não há um desenvolvedor que não saiba que a solução
para o problema é testar seus códigos.
...
Por que não testamos?
É interessante a quantidade de tempo que gastamos
criando soluções tecnológicas para resolver proble...
Testes automatizados
●

●

●

●

Uma maneira para conseguir testar o sistema todo de
maneira constante e contínua a um pre...
Testes automatizados
●

●

Mas a equipe de desenvolvimento não gastará tempo
escrevendo código de teste?
Antes ela só gast...
Testes automatizados
●

A resposta para essa pergunta é:

O que é produtividade?
–

Se produtividade for medida através do...
Testes automatizados X TDD
●

Teste automatizado

Problema

●

Pensa em
uma solução

Codifica a
solução

Pensa nos
Possíve...
Conclusão
●

Um médico, ao longo de uma cirurgia, nunca abre mão de
qualidade. Se o paciente falar para ele: “Doutor, o se...
Conclusão
●

●

●

●

Em nossa área, é justamente o contrário.
Qual desenvolvedor nunca escreveu um código de má
qualidade...
Conclusão
●

Não há desculpas para não testar software.

●

A solução para que seus testes sejam sustentáveis é automatiza...
Teste de unidade
●

●

●

Desenvolvedores, quando pensam em teste de software,
geralmente imaginam um teste que cobre o si...
Teste de unidade
●

●

A ideia é termos baterias de testes de unidade
separadas para cada uma das classes do sistema;
Cada...
Teste de unidade
●

Desenvolvedores gastam toda sua vida automatizando
processos de outras áreas de negócio, criando siste...
Primeiro teste de unidade
●

●

●

●

Neste primeiro teste vamos de um simples código
baseado em “echo” e vamos até um tes...
Primeiro teste de unidade
Primeiro teste de unidade
●

Testando o vetor parte 1:
<?php
<?php
$componente = array();
$componente = array();
// espera...
Primeiro teste de unidade
●

Testando o vetor parte 2:
–

Um jeito bem simples te testar que estamos obtendo os resultados...
Primeiro teste de unidade
●

Testando o vetor parte 3
–

Vamos mudar de testes que exigem interpretação manual para testes...
Primeiro teste de unidade
●

Testando o vetor parte 4:
–

Agora fatoramos a saída de comparação dos valores esperado e rea...
Primeiro teste de unidade
●

●

●

O teste agora está totalmente automatizado. Em vez de
apenas testar como fizemos em nos...
PHPUnit
●

O que é o PHPUnit?
–

É um framework open source que automatiza os
testes de unidade, executando uma bateria de...
PHPUnit
●

Objetivos
–

O PHPUnit tem objetivos de fazer os testes escritos
serem:
●
●
●
●
●
●
●

Fácil de aprender a escr...
PHPUnit
●

Instalação
–

Composer:
●

Adicionar o phpunit como uma dependência local
por projeto no arquivo composer.json:...
PHPUnit
●

Instalação
–

Pear
●

Também existe a possibilidade de instalar o
PHPUnit pelo pear, a nível de S.O

pear confi...
Asserções
●

A maioria dos casos de teste escrito para PHPUnit são
derivadas
indiretamente
da
classe
PHPUnit_Framework_Ass...
Asserções
●

assertEquals
–

assertEquals($esperado, $real)

–

Relata um erro se as variáveis $esperado e $real não
forem...
Asserções
●

assertFalse
–

assertFalse(booleano $condicao)

–

Relata um erro se a $condicao for TRUE.

<?php
<?php
class...
Asserções
●

assertInstanceOf
–

assertInstanceOf($esperado, $real)

–

Relata um erro se $real não for uma instância de
$...
Asserções
●

assertCount()
–

assertCount($contaEsperada, $colecao)

–

Relata um erro se o número de elementos em
$coleca...
Asserções
●

assertEmpty()
–

assertEmpty($colecao)

–

Relata um erro se $colecao não estiver vazio.

<?php
<?php
class V...
Asserções
●

assertNull
–

assertNull($variavel)

–

Relata um erro se $variavel não for NULL.

<?php
<?php
class NuloTest...
Asserções
●

assertTrue
–

assertTrue(booleano $condicao)

–

Relata um erro se $condicao é FALSE.

<?php
<?php
class Verd...
Asserções
●

Mais asserções:
–

http://phpunit.de/manual/3.7/pt_br/index.html
Escrevendo Testes com PHPUnit
●

Testando o vetor com PHPUnit

<?php
<?php
class VetorTest extends PHPUnit_Framework_TestC...
Escrevendo Testes com PHPUnit
●

Dependência de testes
–

O PHPUnit suporta a declaração explícita de dependências entre
m...
Escrevendo Testes com PHPUnit
●

Provedores de dados
–

Um método de teste pode aceitar argumentos
arbitrários. Esses argu...
Escrevendo Testes com PHPUnit
●

Testando Exceções
–

Usa-se a anotação @expectedException para testar
se uma exceção foi ...
Exemplo 1: Conta Bancaria
●

Vamos utilizar os conceitos de TDD em uma classe que
representa uma conta bancária. O contrat...
Exemplo 1: Conta Bancaria
●

Como estamos utilizando os conceitos de TDD vamos
escrevemos os testes para a classe ContaBan...
Exemplo 1: Conta Bancaria
●

Agora vamos escrever somente o mínimo de código
necessário para o primeiro teste, testSaldoIn...
Exemplo 1: Conta Bancaria

<?php
<?php
class ContaBancaria
class ContaBancaria
{{
protected $saldo = 0;
protected $saldo =...
Exemplo 1: Conta Bancaria
●

●

O teste para a primeira condição do contrato agora
passa, mas os testes para a segunda con...
Exemplo 1: Conta Bancaria
●

Agora os testes que asseguram a segunda condição do
contrato também passam.
Exemplo 2: Carrinho de compras
●

●

●

Neste exemplo vamos discutir como os testes podem
efetivamente ajudar desenvolvedo...
Exemplo 2: Carrinho de compras
●

As classes Item e Carrinho estão desta maneira:
–

Item

–

CarrinhoDeCompras
Exemplo 2: Carrinho de compras
●

O cliente solicitou uma funcionalidade que devolva o
valor do item de maior valor dentro...
Exemplo 2: Carrinho de compras
●

Seguindo a técnica do TDD, vamos começar pelo
cenário mais simples, que nesse caso é o c...
Exemplo 2: Carrinho de compras
<?php
require getcwd().'/carrinhodecompras/src/CarrinhoDeCompras.php';
require getcwd().'/c...
Exemplo 2: Carrinho de compras
●

Fazer este teste passar é muito simples, basta retornar
0;

<?php
class MaiorPreco{
publ...
Exemplo 2: Carrinho de compras
O teste deverá passar, agora vamos escrever o teste que
é o caso do carrinho conter apenas ...
Exemplo 2: Carrinho de compras
●

Para este teste passar, vamos ter que escrever um
pouco mais de código, mas ele continua...
Exemplo 2: Carrinho de compras
●

E finalmente, o cenário que resta, precisamos encontrar
o item de maior valor caso o car...
Exemplo 2: Carrinho de compras
Para este teste passar, na implementação vamos
navegar pelos itens da coleção, procurando p...
Exemplo 2: Carrinho de compras
●

Com esta implementação, todos os testes devem passar.
Exemplo 2: Carrinho de compras
●

Com os testes passando, vamos avaliá-los:
–

1º: O teste instancia a classe MaiorPreco, ...
Exemplo 2: Carrinho de compras
●

●

Por que não implementamos o método encontra dentro
da própria classe carrinho?
Vamos ...
Exemplo 2: Carrinho de compras
public function maiorValor(){
if(count($this->itens) == 0)
return 0;
$maior = 0;
foreach($t...
Exemplo 2: Carrinho de compras
●

E os testes:
–

CarrinhoDeComprasTest
Exemplo 2: Carrinho de compras
●

●

●

Agora nosso teste está muito mais claro;
Ao visualizarmos um teste com uma caracte...
Exemplo 3: Nota Fiscal
●

Neste exemplo, vamos, de maneira simplificada, simular
a emissão de uma nota fiscal. Uma possíve...
Exemplo 3: Nota Fiscal
●

●

Vamos imaginar que o processo consiste em gerar a
nota, persistir no banco de dados e enviá-l...
Exemplo 3: Nota Fiscal
●

Para melhor compreendimento do exemplo, vamos
simplificar às classes de persistência e de e-mail...
Exemplo 3: Nota Fiscal

–

Email.php

<?php
class Email{
public function enviar($nf){
//Envia nota para o cliente ou outro...
Exemplo 3: Nota Fiscal
●

●

●

Agora
vamos
iniciar
GeradorDeNotaFiscal;

a

escrita

da

classe

Vamos imaginar que a reg...
Exemplo 3: Nota Fiscal
<?php
require getcwd().'/notafiscal/src/GeradorDeNotaFiscal.php';
require getcwd().'/notafiscal/src...
Exemplo 3: Nota Fiscal
Fazer este teste passar é fácil, basta instanciar uma nota
fiscal com 18% a menos do valor do pedid...
Exemplo 3: Nota Fiscal
●

O teste passa. O próximo passo é persistir os dados
dessa nota fiscal. A classe persiste já exis...
Exemplo 3: Nota Fiscal
<?php
12

require getcwd().'/notafiscal/src/NotaFiscal.php';
require getcwd().'/notafiscal/src/Pers...
Exemplo 3: Nota Fiscal
●

Ok, mas pera... a gente não implementou a classe
Persiste, sua funcionalidade não é responsabili...
Exemplo 3: Nota Fiscal
●

Mocks
–

A ideia dos testes de unidade é testar a classe de
maneira isolada, sem qualquer interf...
Exemplo 3: Nota Fiscal
●

Moks
–

Para conseguir fazer o teste passar, vamos criar um
“duble” para a classe Persiste, um c...
Exemplo 3: Nota Fiscal
●

O nosso teste de persistência da classe geradora da
nota ficará desta forma:
Exemplo 3: Nota Fiscal
public function testDevePersistirNFGerada(){
$mock = $this->mockPeriste();
$GeradorDeNotaFiscal = n...
Exemplo 3: Nota Fiscal
●

Para conseguirmos testar utilizando o mock, a classe
que simulamos deverá ser uma dependência na...
Exemplo 3: Nota Fiscal
class GeradorDeNotaFiscal{
protected $persiste;
public function __construct($persiste){
$this->pers...
Exemplo 3: Nota Fiscal
●

Mocks
–

A arte de mockar as dependências é conhecida como
“TDD ao estilo londrino”, isso porquê...
Exemplo 3: Nota Fiscal
●

●

Mocks são extremamente úteis, com ele não precisamos
nos preocupar com o funcionamento de cla...
Análise e cobertura de código
●

●

Como você descobre o código que ainda não foi testado
ou, em outras palavras, ainda nã...
Análise e cobertura de código
●

●

O PHPUnit permite gerar relatórios que informam quais
linhas do seu código foram testa...
Coding Dojo
●

Um coding dojo é um encontro de desenvolvedores que
estão interessados em aprender alguma coisa nova,
como ...
Coding Dojo
●

●

A prática mais comum é juntar alguns desenvolvedores e
projetar uma máquina na parede. Dois desenvolvedo...
Coding Dojo
●

No nosso Coding Dojo, vamos resolver o problema dos
números romanos utilizando os conceitos vistos até aqui...
O problema dos números romanos
●

Numerais romanos foram criados na Roma Antiga e eles foram
utilizados em todo o seu impé...
O problema dos números romanos
●

Para representar outros números, os romanos
combinavam estes símbolos, começando do alga...
O problema dos números romanos
●

Utilizando conceitos de TDD, desenvolver um software
onde dado um numeral romano, o prog...
O problema dos números romanos
●

Primeiro teste:
<?php
<?php
require getcwd().'/n_romanos/src/ConversorDeNumeroRomano.php...
O problema dos números romanos
Implementar a classe ConversorDeNumeroRomano da
maneira mais simples para que o primeiro te...
O problema dos números romanos
Adicionando o segundo teste:

●

public function testDeveEntenderOSimboloI() {{
public func...
O problema dos números romanos
●

Implementar a classe ConversorDeNumeroRomano da
maneira mais simples para que os dois pr...
O problema dos números romanos
Para não precisarmos utilizar vários ifs encadeados ou um switch
case vamos armazenar todos...
O problema dos números romanos
●

Adicionando o terceiro e quarto teste :

...
...
public function testDeveEntenderOSimbol...
O problema dos números romanos
●

Implementando a solução mais simples para fazer todos
os testes passarem:

public functi...
O problema dos números romanos
●

Adicionando testes com números de menor valor a
esquerda e a direita:

...
...
public fu...
O problema dos números romanos
●

Implementando a solução mais simples para fazer todos
os testes passarem:
public functio...
O problema dos números romanos
●

Todos os testes já passam, o algoritmo criado até então
já atende o cenário do teste.
O problema dos números romanos
●

Refletindo sobre o assunto
–

Que vantagens temos programando assim?
●
●
●
●

Foco no te...
Brainstorming
Dúvidas?
●

cezar08@unochapeco.edu.br

●

http://www.slideshare.net/cezar08
Referências
●

http://phpunit.de/manual (2013);

●

Bergmann, PHPUnit Manual (2005);

●

●

●

●

●

BECK, Kent. Test Driv...
Próximos SlideShares
Carregando em…5
×

Test-Driven Development with PHP

1.161 visualizações

Publicada em

Mini Curso sobre TDD e PHPUnit, básico, ministrado no PHPSC Conf 2013.

Publicada em: Tecnologia
0 comentários
1 gostou
Estatísticas
Notas
  • Seja o primeiro a comentar

Sem downloads
Visualizações
Visualizações totais
1.161
No SlideShare
0
A partir de incorporações
0
Número de incorporações
4
Ações
Compartilhamentos
0
Downloads
15
Comentários
0
Gostaram
1
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Test-Driven Development with PHP

  1. 1. Test Driven Development with PHP Cezar Junior de Souza E-mail: cezar08@unochapeco.edu.br
  2. 2. Quem sou eu ● ● Desenvolvedor PHP há 4 anos; Bacharel em Sistemas de Informação pela Unochapecó; ● Especialista em Engenharia e Qualidade de Software; ● Programador na Unochapecó;
  3. 3. Quem sou eu ● Tem experiência com: – Zend Framework 1; – Zend Framework 2; – Ruby on Rails 3.2; – Dojo; – ExtJs; – Jquery; – Doctrine 2; – PHPUnit; – Gerência de projetos com SCRUM...
  4. 4. O que vamos ver ● Introdução – – Ciclo – Por que devemos testar? – Por que não testamos? – Testes automatizados – Testes automatizados X TDD – ● O que é? Conclusão Teste de unidade – Primeiro teste de unidade
  5. 5. O que vamos ver ● PHPUnit – O que é? – Objetivos – Instalação – Asserções ● ● ● ● ● ● ● – assertEquals assertFalse assertInstanceOf assertCount assertEmpty assertNull assertTrue
  6. 6. O que vamos ver ● PHPUnit – Escrevendo Testes com PHPUnit ● ● ● Dependência de testes Provedores de dados Testando Exceções
  7. 7. O que vamos ver ● Exemplos – Exemplo 1: Conta Bancária – Exemplo 2: Carrinho de compras – Exemplo 3: Nota fiscal Mocks Análise e cobertura de código ● ● ● Coding Dojo – O problema dos números romanos ● Brainstorming ● Referências
  8. 8. Introdução ● O que é TDD? – É uma das práticas de desenvolvimento de software sugeridas por diversas metodologias. – Prega a ideia de fazer com que o desenvolvedor escreva testes automatizados de maneira constante ao longo do desenvolvimento. – Sugere que “o desenvolvedor escreva o teste antes mesmo da implementação”.
  9. 9. Introdução ● O que é TDD? – É desenvolvido organicamente, com o feedback do código executável exibido entre as decisões. – O desenvolvedor escreve os próprios testes porque não pode esperar 20 vezes por dia por alguém para escrevê-los. – Utilizando a técnica as baterias de testes tendem a ser maiores, cobrindo mais casos, e garantindo uma maior qualidade externa
  10. 10. Introdução ● O que é o TDD? – A prática nos ajuda a escrever um software melhor, com mais qualidade, e um código melhor, mais fácil de ser mantido e evoluído.
  11. 11. Introdução “Toda prática que ajuda a aumentar a qualidade do software produzido deve ser estudada.”(Aniche, 2012)
  12. 12. Ciclo Escrever o teste->Teste Falha->Escreve o programa->Teste passa->Refatora
  13. 13. Por que devemos testar? ● ● É necessária somente uma resposta para esta pergunta, para ter a certeza que o nosso código faz o que deve fazer. A quantidade de software que não funciona é incrível.
  14. 14. Por que devemos testar? ● Os Estados Unidos estimam que bugs de software lhes custam aproximadamente 60 bilhões de dólares por ano... Fonte: Computer World. Study: Buggy software costs users, vendors nearly 60b annually. http://www.computerworld.com/s/article/72245/Study_Buggy_software_ costs_users_vendors_nearly_60B_annually.
  15. 15. Por que devemos testar? ● Um erro de software pode matar pessoas – o foguete Ariane 5 explodiu por um erro de software; – um hospital panamenho matou pacientes pois seu software para dosagem de remédios errou.
  16. 16. Por que não testamos? ● ● ● Não há um desenvolvedor que não saiba que a solução para o problema é testar seus códigos. Não testamos, porque testar sai caro. Testar sai caro porque estamos pagando “a pessoa” errada para fazer o trabalho.
  17. 17. Por que não testamos? É interessante a quantidade de tempo que gastamos criando soluções tecnológicas para resolver problemas “dos outros”. Por que não escrevemos programas que resolvam também os nossos problemas?
  18. 18. Testes automatizados ● ● ● ● Uma maneira para conseguir testar o sistema todo de maneira constante e contínua a um preço justo é automatizando os testes. O teste automatizado executaria muito rápido; Se ele executa constantemente; rápido, logo o rodaríamos Se os rodarmos o tempo todo, descobriríamos os problemas mais cedo, diminuindo o custo que o bug geraria.
  19. 19. Testes automatizados ● ● Mas a equipe de desenvolvimento não gastará tempo escrevendo código de teste? Antes ela só gastava tempo com código de produção, essa equipe ficará menos produtiva?
  20. 20. Testes automatizados ● A resposta para essa pergunta é: O que é produtividade? – Se produtividade for medida através do número de linhas de código de produção escritos por dia, talvez o desenvolvedor seja sim menos produtivo, mas, se produtividade for a quantidade de linhas de código de produção sem defeitos escritos por dia, o desenvolvedor será mais produtivo ao utilizar testes automatizados.
  21. 21. Testes automatizados X TDD ● Teste automatizado Problema ● Pensa em uma solução Codifica a solução Pensa nos Possíveis casos De erro Codifica os testes Testa Codifica a solução Testa Refatora TDD Problema Pensa em uma solução Pensa nos Possíveis casos De erro Codifica os testes Refatora
  22. 22. Conclusão ● Um médico, ao longo de uma cirurgia, nunca abre mão de qualidade. Se o paciente falar para ele: “Doutor, o senhor poderia não lavar a mão e terminar a cirurgia 30 minutos mais cedo?”, tenho certeza que o médico negaria na hora. Ele saberia que chegaria ao resultado final mais rápido, mas a chance de um problema é tão grande, que simplesmente não valeria a pena.
  23. 23. Conclusão ● ● ● ● Em nossa área, é justamente o contrário. Qual desenvolvedor nunca escreveu um código de má qualidade de maneira consciente? Quem nunca escreveu uma “gambiarra"? Quem nunca colocou software em produção sem executar o mínimo suficiente de testes para tal?
  24. 24. Conclusão ● Não há desculpas para não testar software. ● A solução para que seus testes sejam sustentáveis é automatizando; ● ● Testar é divertido, aumenta a qualidade do seu produto, e pode ainda ajudá-lo a identificar trechos de código que foram mal escritos ou projetados; Te livram várias vezes da chatice do seu inimigo natural, o “testador”; Testador Programadores ● Enfim, é muita vantagem.
  25. 25. Teste de unidade ● ● ● Desenvolvedores, quando pensam em teste de software, geralmente imaginam um teste que cobre o sistema como um todo. Um teste de unidade não se preocupa com todo o sistema; ele está interessado apenas em saber se uma pequena parte do sistema funciona. Um teste de unidade testa uma única unidade do nosso sistema. Geralmente, em sistemas orientados a objetos, essa unidade é a classe.
  26. 26. Teste de unidade ● ● A ideia é termos baterias de testes de unidade separadas para cada uma das classes do sistema; Cada bateria preocupada apenas com a sua classe.
  27. 27. Teste de unidade ● Desenvolvedores gastam toda sua vida automatizando processos de outras áreas de negócio, criando sistemas para RHs, controle de caixa, entre outros, com o intuito de facilitar a vida daqueles profissionais. Por que não criar software que automatize o seu próprio ciclo de trabalho? ● Testes automatizados são fundamentais para um desenvolvimento de qualidade, sua existência traz diversos benefícios, como aumento da qualidade e a diminuição de bugs em produção.
  28. 28. Primeiro teste de unidade ● ● ● ● Neste primeiro teste vamos de um simples código baseado em “echo” e vamos até um teste totalmente automatizado; Imagine que temos que testar um vetor do PHP, uma pequena funcionalidade a se testar é a função count(); Para um vetor recém criado esperamos que a função count retorne 0; Após adicionarmos um elemento, count deverá retornar 1;
  29. 29. Primeiro teste de unidade
  30. 30. Primeiro teste de unidade ● Testando o vetor parte 1: <?php <?php $componente = array(); $componente = array(); // espera-se que $componente esteja vazio. // espera-se que $componente esteja vazio. $componente[] = 'elemento'; $componente[] = 'elemento'; // espera-se que $componente contenha um elemento. // espera-se que $componente contenha um elemento. ?> ?>
  31. 31. Primeiro teste de unidade ● Testando o vetor parte 2: – Um jeito bem simples te testar que estamos obtendo os resultados que esperamos é imprimir o resultado antes e depois de adicionarmos o elemento. Se obtivermos 0 e depois 1, a função count se comporta como o esperado. <?php <?php $componente = array(); $componente = array(); echo count($componente). “n”; echo count($componente). “n”; $componente[] = 'elemento'; $componente[] = 'elemento'; echo count($componente). “n”; echo count($componente). “n”; //Saídas: //Saídas: // 0 // 0 //1 //1 ?> ?>
  32. 32. Primeiro teste de unidade ● Testando o vetor parte 3 – Vamos mudar de testes que exigem interpretação manual para testes que podem executar automaticamente. Escrevemos a comparação do valor esperado e do real em nosso código de teste e imprimimos ok se os valores forem iguais. Se alguma vez virmos uma mensagem não ok saberemos que algo está errado. <?php <?php $componente = array(); $componente = array(); echo count($componente) == 0 ? “ok n” : :“não ok n”; echo count($componente) == 0 ? “ok n” “não ok n”; $componente[] = 'elemento'; $componente[] = 'elemento'; echo count($componente) == 1 ? “ok n” : :“não ok n”; echo count($componente) == 1 ? “ok n” “não ok n”; //Saídas: //Saídas: // ok // ok //ok //ok ?> ?>
  33. 33. Primeiro teste de unidade ● Testando o vetor parte 4: – Agora fatoramos a saída de comparação dos valores esperado e real em uma função que gera uma Exception onde há uma discrepância. Isso nos traz dois benefícios: a escrita dos testes se torna mais fácil e só obteremos saída quando algo estiver errado. <?php <?php $componente = array(); $componente = array(); assertTrue(count($componente) == 0); assertTrue(count($componente) == 0); $componente[] = 'elemento'; $componente[] = 'elemento'; assertTrue(count($componente) == 1); assertTrue(count($componente) == 1); function assertTrue($condicao) function assertTrue($condicao) {{ ifif(!$condicao) {{ (!$condicao) throw new Exception('Asserção falhou.'); throw new Exception('Asserção falhou.'); }} }} //Saídas: ... //Saídas: ...
  34. 34. Primeiro teste de unidade ● ● ● O teste agora está totalmente automatizado. Em vez de apenas testar como fizemos em nossa primeira versão, com esta versão temos um teste automatizado. Até agora só tivemos dois testes para o vetor e a função count() . Quando começarmos a testar as numerosas funções array_*() que o PHP oferece, precisaremos escrever um teste para cada uma delas. Porém, é muito melhor utilizar o que já existe. Existe um framework com todos esses testes já prontos para utilização, este cara é o PHPUnit.
  35. 35. PHPUnit ● O que é o PHPUnit? – É um framework open source que automatiza os testes de unidade, executando uma bateria de testes para os desenvolvedores.
  36. 36. PHPUnit ● Objetivos – O PHPUnit tem objetivos de fazer os testes escritos serem: ● ● ● ● ● ● ● Fácil de aprender a escrever; Fáceis de escrever; Fáceis de ler; Fáceis de executar; Rápidos de executar; Isolados; Combináveis.
  37. 37. PHPUnit ● Instalação – Composer: ● Adicionar o phpunit como uma dependência local por projeto no arquivo composer.json: { "require-dev": { "phpunit/phpunit": "3.7.*" } }
  38. 38. PHPUnit ● Instalação – Pear ● Também existe a possibilidade de instalar o PHPUnit pelo pear, a nível de S.O pear config-set auto_discover 1 pear install pear.phpunit.de/PHPUnit
  39. 39. Asserções ● A maioria dos casos de teste escrito para PHPUnit são derivadas indiretamente da classe PHPUnit_Framework_Assert, que contém métodos para verificar automaticamente os valores e relatórios de discrepâncias.
  40. 40. Asserções ● assertEquals – assertEquals($esperado, $real) – Relata um erro se as variáveis $esperado e $real não forem iguais. <?php <?php class IgualaTest extends PHPUnit_Framework_TestCase class IgualaTest extends PHPUnit_Framework_TestCase {{ public function testFalha() public function testFalha() {{ $this->assertEquals(1, 0); $this->assertEquals(1, 0); }} }} ?> ?>
  41. 41. Asserções ● assertFalse – assertFalse(booleano $condicao) – Relata um erro se a $condicao for TRUE. <?php <?php class FalsoTest extends PHPUnit_Framework_TestCase class FalsoTest extends PHPUnit_Framework_TestCase {{ public function testFalha() public function testFalha() {{ $this->assertFalse(TRUE); $this->assertFalse(TRUE); }} }} ?> ?>
  42. 42. Asserções ● assertInstanceOf – assertInstanceOf($esperado, $real) – Relata um erro se $real não for uma instância de $esperado. <?php <?php class InstanciaDeTest extends PHPUnit_Framework_TestCase class InstanciaDeTest extends PHPUnit_Framework_TestCase {{ public function testFalha() public function testFalha() {{ $this->assertInstanceOf('RuntimeException', new Exception); $this->assertInstanceOf('RuntimeException', new Exception); }} }} ?> ?>
  43. 43. Asserções ● assertCount() – assertCount($contaEsperada, $colecao) – Relata um erro se o número de elementos em $colecao não for $contaEsperada. <?php <?php class ContaTest extends PHPUnit_Framework_TestCase class ContaTest extends PHPUnit_Framework_TestCase {{ public function testFalha() public function testFalha() {{ $this->assertCount(0, array('foo')); $this->assertCount(0, array('foo')); }} }} ?> ?>
  44. 44. Asserções ● assertEmpty() – assertEmpty($colecao) – Relata um erro se $colecao não estiver vazio. <?php <?php class VazioTest extends PHPUnit_Framework_TestCase class VazioTest extends PHPUnit_Framework_TestCase {{ public function testFalha() public function testFalha() {{ $this->assertEmpty(array('foo')); $this->assertEmpty(array('foo')); }} }} ?> ?>
  45. 45. Asserções ● assertNull – assertNull($variavel) – Relata um erro se $variavel não for NULL. <?php <?php class NuloTest extends PHPUnit_Framework_TestCase class NuloTest extends PHPUnit_Framework_TestCase {{ public function testFalha() public function testFalha() {{ $this->assertNull('foo'); $this->assertNull('foo'); }} }} ?> ?>
  46. 46. Asserções ● assertTrue – assertTrue(booleano $condicao) – Relata um erro se $condicao é FALSE. <?php <?php class VerdadeiroTest extends PHPUnit_Framework_TestCase class VerdadeiroTest extends PHPUnit_Framework_TestCase {{ public function testFalha() public function testFalha() {{ $this->assertTrue(FALSE); $this->assertTrue(FALSE); }} }} ?> ?>
  47. 47. Asserções ● Mais asserções: – http://phpunit.de/manual/3.7/pt_br/index.html
  48. 48. Escrevendo Testes com PHPUnit ● Testando o vetor com PHPUnit <?php <?php class VetorTest extends PHPUnit_Framework_TestCase class VetorTest extends PHPUnit_Framework_TestCase {{ public function testVazio() public function testVazio() {{ $componente = array(); $componente = array(); $this->assertEquals(0, count($componente)); $this->assertEquals(0, count($componente)); }} }} public function testPopulado() public function testPopulado() {{ $componente[] = 'elemento'; $componente[] = 'elemento'; $this->assertInternalType('array', $componente); $this->assertInternalType('array', $componente); $this->assertEquals(1, count($componente)); $this->assertEquals(1, count($componente)); }}
  49. 49. Escrevendo Testes com PHPUnit ● Dependência de testes – O PHPUnit suporta a declaração explícita de dependências entre métodos de teste, ou seja, você pode informar ao interpretador que um teste depende de outro para funcionar. Exemplo
  50. 50. Escrevendo Testes com PHPUnit ● Provedores de dados – Um método de teste pode aceitar argumentos arbitrários. Esses argumentos devem ser fornecidos por um método provedor de dados – O método provedor de dados a ser usado é especificado usando a anotação @dataProvider. Exemplo
  51. 51. Escrevendo Testes com PHPUnit ● Testando Exceções – Usa-se a anotação @expectedException para testar se uma exceção foi lançada dentro do código de teste. Exemplo
  52. 52. Exemplo 1: Conta Bancaria ● Vamos utilizar os conceitos de TDD em uma classe que representa uma conta bancária. O contrato para a classe ContaBancaria não apenas exige métodos get e set para o saldo da conta, mas também métodos para depositar e sacar dinheiro. Também especifica as duas seguintes condições que devem ser garantidas: – O saldo inicial da conta bancária deve ser zero. – O saldo da conta bancária não pode se tornar negativo.
  53. 53. Exemplo 1: Conta Bancaria ● Como estamos utilizando os conceitos de TDD vamos escrevemos os testes para a classe ContaBancaria antes de escrevermos o código propriamente dito da classe. Nós usamos as condições do contrato como base para os testes e nomeamos os testes conforme o mesmo. Teste para a classe conta bancaria
  54. 54. Exemplo 1: Conta Bancaria ● Agora vamos escrever somente o mínimo de código necessário para o primeiro teste, testSaldoInicialZero(), passar. Em nosso exemplo essa quantidade equivale a implementar o método getSaldo() da classe ContaBancaria.
  55. 55. Exemplo 1: Conta Bancaria <?php <?php class ContaBancaria class ContaBancaria {{ protected $saldo = 0; protected $saldo = 0; public function getSaldo() public function getSaldo() {{ return $this->saldo; return $this->saldo; }} }} ?> ?>
  56. 56. Exemplo 1: Conta Bancaria ● ● O teste para a primeira condição do contrato agora passa, mas os testes para a segunda condição do contrato falham, porque ainda temos que implementar os métodos que esses testes chamam. Para que os testes que asseguram a segunda condição do contrato passem, agora precisamos implementar os métodos sacarDinheiro(), depositarDinheiro(), e setSaldo(). Exemplo conta bancaria
  57. 57. Exemplo 1: Conta Bancaria ● Agora os testes que asseguram a segunda condição do contrato também passam.
  58. 58. Exemplo 2: Carrinho de compras ● ● ● Neste exemplo vamos discutir como os testes podem efetivamente ajudar desenvolvedores a pensar melhor em relação as classes que estão criando. Vamos supor que o nosso projeto atual seja uma loja on-line. Esta loja possuí um carrinho de compras que guarda uma coleção de itens comprados. Um item tem as seguintes propriedades: descrição, quantidade e valor unitário. O item também deve ter um método que retorne o valor total.
  59. 59. Exemplo 2: Carrinho de compras ● As classes Item e Carrinho estão desta maneira: – Item – CarrinhoDeCompras
  60. 60. Exemplo 2: Carrinho de compras ● O cliente solicitou uma funcionalidade que devolva o valor do item de maior valor dentro desse carrinho de compras. Já pensando nos testes, temos os seguintes cenários: – Um carrinho sem nenhum item deve retornar zero; – Se o carrinho só tiver um item, ele mesmo será o item de maior valor; – Se o carrinho tiver muitos itens, o item de maior valor é o que deve ser retornado.
  61. 61. Exemplo 2: Carrinho de compras ● Seguindo a técnica do TDD, vamos começar pelo cenário mais simples, que nesse caso é o carrinho vazio. Vamos criar um teste para a classe MaiorPreco, responsável por essa tarefa:
  62. 62. Exemplo 2: Carrinho de compras <?php require getcwd().'/carrinhodecompras/src/CarrinhoDeCompras.php'; require getcwd().'/carrinhodecompras/src/Item.php'; require getcwd().'/carrinhodecompras/src/MaiorPreco.php'; class MaiorPrecoTest extends PHPUnit_Framework_TestCase{ public function testDeveRetornarZeroSeCarrinhoVazio(){ $CarrinhoDeCompras = new CarrinhoDeCompras(); $MaiorPreco = new MaiorPreco(); $valor = $MaiorPreco->encontra($CarrinhoDeCompras); $this->assertEquals(0.0, $valor); } }
  63. 63. Exemplo 2: Carrinho de compras ● Fazer este teste passar é muito simples, basta retornar 0; <?php class MaiorPreco{ public function encontra(CarrinhoDeCompras $carrinho){ return 0; } } ?>
  64. 64. Exemplo 2: Carrinho de compras O teste deverá passar, agora vamos escrever o teste que é o caso do carrinho conter apenas um produto: ● public function testDeveRetornarValorDoItemSeCarrinhoCom1Elemento(){ $CarrinhoDeCompras = new CarrinhoDeCompras(); $carrinho = $CarrinhoDeCompras->adiciona(new Item("Kindle", 1, 299.00)); $MaiorPreco = new MaiorPreco(); $valor = $MaiorPreco->encontra($carrinho); $this->assertEquals(299.00, $valor); }
  65. 65. Exemplo 2: Carrinho de compras ● Para este teste passar, vamos ter que escrever um pouco mais de código, mas ele continua sendo simples: <?php class MaiorPreco{ public function encontra(CarrinhoDeCompras $carrinho){ if(count($carrinho->getItens()) == 0) return 0; $itens = $carrinho->getItens(); return $itens[0]->getValorTotal(); } }
  66. 66. Exemplo 2: Carrinho de compras ● E finalmente, o cenário que resta, precisamos encontrar o item de maior valor caso o carrinho contenha muitos itens, vamos adicionar mais este teste para a classe: public function testDeveRetornarMaiorValorSeCarrinhoContemMuitosElementos(){ $CarrinhoDeCompras = new CarrinhoDeCompras(); $carrinho = $CarrinhoDeCompras->adiciona(new Item("Kindle", 2, 299.00)); $carrinho = $CarrinhoDeCompras->adiciona(new Item("Galaxy", 1, 1400.00)); $carrinho = $CarrinhoDeCompras->adiciona(new Item("Google Glass", 1, 1100.00)); $MaiorPreco = new MaiorPreco3(); $valor = $MaiorPreco->encontra($carrinho); $this->assertEquals(1400.00, $valor); }
  67. 67. Exemplo 2: Carrinho de compras Para este teste passar, na implementação vamos navegar pelos itens da coleção, procurando pelo item de maior valor total: ● public function encontra(CarrinhoDeCompras $carrinho){ if(count($carrinho) == 0) return 0; $maior = 0; foreach($carrinho->getItens() as $item){ if($maior < $item->getValorTotal()) $maior = $item->getValorTotal(); } return $maior; }
  68. 68. Exemplo 2: Carrinho de compras ● Com esta implementação, todos os testes devem passar.
  69. 69. Exemplo 2: Carrinho de compras ● Com os testes passando, vamos avaliá-los: – 1º: O teste instancia a classe MaiorPreco, passa para ela um objeto carrinho e verifica o retorno do método; – 2º: Podemos ver que todo o cenário montado foi em cima da classe CarrinhoDeCompras, não fazemos nada na classe MaiorPreco; – 3º: Isso é um mau sinal, a classe MaiorPreco parece inútil já que não houve necessidade de setar atributos ou qualquer outro dado nela;
  70. 70. Exemplo 2: Carrinho de compras ● ● Por que não implementamos o método encontra dentro da própria classe carrinho? Vamos fazer essa mudança, vamos levar a lógica do método encontra dentro do CarrinhoDeCompras, o método ficará assim:
  71. 71. Exemplo 2: Carrinho de compras public function maiorValor(){ if(count($this->itens) == 0) return 0; $maior = 0; foreach($this->itens as $item){ if($maior < $item->getValorTotal()) $maior = $item->getValorTotal(); } return $maior; }
  72. 72. Exemplo 2: Carrinho de compras ● E os testes: – CarrinhoDeComprasTest
  73. 73. Exemplo 2: Carrinho de compras ● ● ● Agora nosso teste está muito mais claro; Ao visualizarmos um teste com uma característica estranha, mudamos nosso design de classes; Muitos desenvolvedores afirmam que o TDD pode guiá-los no projeto de classes, mas isso não vai depender muito mais da experiência e conhecimento do desenvolvedor do que a utilização da técnica.
  74. 74. Exemplo 3: Nota Fiscal ● Neste exemplo, vamos, de maneira simplificada, simular a emissão de uma nota fiscal. Uma possível representação de Nota Fiscal e Pedido pode ser semelhante a estas classes: – NotaFiscal – Pedido
  75. 75. Exemplo 3: Nota Fiscal ● ● Vamos imaginar que o processo consiste em gerar a nota, persistir no banco de dados e enviá-la por e-mail; Para isso, seguindo os princípios de responsabilidade única, vamos precisar de três outras classes, uma responsável por enviar o e-mail, outra por persistir os dados no banco de dados e mais uma para gerar o cálculo do valor da nota fiscal;
  76. 76. Exemplo 3: Nota Fiscal ● Para melhor compreendimento do exemplo, vamos simplificar às classes de persistência e de e-mail, elas ficaram desta forma: – Persiste.php <?php class Persiste{ public function persistir($nf){ //persiste os dados em uma base de dados } } ?>
  77. 77. Exemplo 3: Nota Fiscal – Email.php <?php class Email{ public function enviar($nf){ //Envia nota para o cliente ou outro sistema } }
  78. 78. Exemplo 3: Nota Fiscal ● ● ● Agora vamos iniciar GeradorDeNotaFiscal; a escrita da classe Vamos imaginar que a regra de cálculo da nota fiscal seja simples, o valor da nota deve ser 18% do valor do pedido; Vamos começar pelo teste
  79. 79. Exemplo 3: Nota Fiscal <?php require getcwd().'/notafiscal/src/GeradorDeNotaFiscal.php'; require getcwd().'/notafiscal/src/Pedido.php'; class GeradorDeNotaFiscalTest extends PHPUnit_Framework_TestCase{ public function testDeveGerarNFComValorDeImpostoDescontado(){ $GeradorDeNotaFiscal = new GeradorDeNotaFiscal(); $Pedido = new Pedido(); $Pedido->setPedido("Bob", 4000, 1); $NotaFiscal = $GeradorDeNotaFiscal->gerar($Pedido); $this->assertEquals(4000 * 0.82, $NotaFiscal->getValor()); }
  80. 80. Exemplo 3: Nota Fiscal Fazer este teste passar é fácil, basta instanciar uma nota fiscal com 18% a menos do valor do pedido: ● <?php require getcwd().'/notafiscal/src/NotaFiscal.php'; require getcwd().'/notafiscal/src/Persiste.php'; class GeradorDeNotaFiscal{ public function gerar($pedido){ $NotaFiscal = new NotaFiscal(); $NotaFiscal->setNotaFiscal($pedido->getCliente(), $pedido->getValorTotal() * 0.82, date('Y-m-d')); return $NotaFiscal; } }
  81. 81. Exemplo 3: Nota Fiscal ● O teste passa. O próximo passo é persistir os dados dessa nota fiscal. A classe persiste já existe, com seu método persistir(), só precisamos usá-lo. Dessa vez vamos fazer diferente, sem escrever o teste antes, vamos ver como a implementação ficaria
  82. 82. Exemplo 3: Nota Fiscal <?php 12 require getcwd().'/notafiscal/src/NotaFiscal.php'; require getcwd().'/notafiscal/src/Persiste.php'; 10 class GeradorDeNotaFiscal{ 8 6 4 2 Coluna 1 Coluna 2 Coluna 3 public function gerar($pedido){ $NotaFiscal = new NotaFiscal(); $NotaFiscal->setNotaFiscal($pedido-> getCliente(), $pedido->getValorTotal() * 0.94, date('Y-m-d')); $Persiste = new Persiste(); $Persiste->persistir($NotaFiscal); 0 Linha 1 Linha return $NotaFiscal; 2 } } Linha 3 Linha 4
  83. 83. Exemplo 3: Nota Fiscal ● Ok, mas pera... a gente não implementou a classe Persiste, sua funcionalidade não é responsabilidade da classe que estamos escrevendo, então como podemos testar o seu comportamento?
  84. 84. Exemplo 3: Nota Fiscal ● Mocks – A ideia dos testes de unidade é testar a classe de maneira isolada, sem qualquer interferência das classes que a rodeiam; – Em um teste onde as classes estão integradas, qual classe que gerou o problema? – Não há o porquê de os testes do GeradorDeNotaFiscalTest garantir que o dado foi persistido com sucesso, isso é tarefa da classe Persiste, a tarefa do GeradorDeNotaFiscal é somente invocar o método persistir();
  85. 85. Exemplo 3: Nota Fiscal ● Moks – Para conseguir fazer o teste passar, vamos criar um “duble” para a classe Persiste, um clone dela, onde vamos simular o que o método persistir deve retornar;
  86. 86. Exemplo 3: Nota Fiscal ● O nosso teste de persistência da classe geradora da nota ficará desta forma:
  87. 87. Exemplo 3: Nota Fiscal public function testDevePersistirNFGerada(){ $mock = $this->mockPeriste(); $GeradorDeNotaFiscal = new GeradorDeNotaFiscal($mock); $Pedido = new Pedido(); $Pedido->setPedido("Bob", 4000, 1); $NotaFiscal = $GeradorDeNotaFiscal->gerar($Pedido); } private function mockPeriste(){ $mock = $this->getMock('Persiste', array('persistir')); $mock->expects($this->any()) ->method('persistir') ->will($this->returnValue(true)); return $mock; }
  88. 88. Exemplo 3: Nota Fiscal ● Para conseguirmos testar utilizando o mock, a classe que simulamos deverá ser uma dependência na classe que testamos, portanto, devemos passar a classe Persiste no construtor da classe GeradorDeNotaFiscal, ela ficará assim:
  89. 89. Exemplo 3: Nota Fiscal class GeradorDeNotaFiscal{ protected $persiste; public function __construct($persiste){ $this->persiste = $persiste; } public function gerar($pedido){ $NotaFiscal = new NotaFiscal(); $NotaFiscal->setNotaFiscal($pedido->getCliente(), $pedido->getValorTotal() * 0.82, date('Y-m-d')); $this->persiste->persistir($NotaFiscal); return $NotaFiscal; }
  90. 90. Exemplo 3: Nota Fiscal ● Mocks – A arte de mockar as dependências é conhecida como “TDD ao estilo londrino”, isso porquê muitas das discussões importantes na área de mock objects surgiram por lá. Autores famosos como Steve Freeman e Nat Pryce (ambos britânicos) são fãs dessa abordagem.
  91. 91. Exemplo 3: Nota Fiscal ● ● Mocks são extremamente úteis, com ele não precisamos nos preocupar com o funcionamento de classes que ainda não estão prontas, precisamos nos preocupar somente com a unidade que estamos implementando; Podemos criar um mock para a classe e-mail também, mas isso deixo por conta de vocês.
  92. 92. Análise e cobertura de código ● ● Como você descobre o código que ainda não foi testado ou, em outras palavras, ainda não foi coberto por um teste? Como você mede o quanto os testes estão completos?
  93. 93. Análise e cobertura de código ● ● O PHPUnit permite gerar relatórios que informam quais linhas do seu código foram testadas e quais não estão sendo utilizadas gerando estatísticas de tudo isso. Para gerar os relatórios deve ser executado os testes através do comando: – phpvendor/phpunit/phpunit/phpunit.php –coverage-html contabancaria/test/ContaBancariaTest.php ./report
  94. 94. Coding Dojo ● Um coding dojo é um encontro de desenvolvedores que estão interessados em aprender alguma coisa nova, como uma linguagem de programação diferente, ou técnicas de desenvolvimento diferentes. O objetivo é criar um ambiente tranquilo e favorável a novos aprendizados.
  95. 95. Coding Dojo ● ● A prática mais comum é juntar alguns desenvolvedores e projetar uma máquina na parede. Dois desenvolvedores sentam em frente ao computador e começam a resolver algum problema pré-determinado, usando a linguagem e/ou a prática que desejam aprender melhor. Geralmente esses dois desenvolvedores tem apenas alguns minutos para trabalhar. Enquanto eles trabalham a plateia assiste e eventualmente sugere alterações para o “piloto e co-piloto”. Ao final do tempo , o co-piloto vira piloto, o piloto volta para a plateia, e alguém da plateia se torna “co-piloto”.
  96. 96. Coding Dojo ● No nosso Coding Dojo, vamos resolver o problema dos números romanos utilizando os conceitos vistos até aqui.
  97. 97. O problema dos números romanos ● Numerais romanos foram criados na Roma Antiga e eles foram utilizados em todo o seu império. Os números eram representados por sete diferentes símbolos: – I, unus, 1, (um) – V, quinque, 5 (cinco) – X, decem, 10 (dez) – L, quinquaginta, 50 (cinquenta) – C, centum, 100 (cem) – D, quingenti, 500 (quinhentos) – M, mille, 1.000 (mil)
  98. 98. O problema dos números romanos ● Para representar outros números, os romanos combinavam estes símbolos, começando do algarismo de maior valor e seguindo as regras: – Algarismos de menor ou igual valor à direita são somados ao algarismo de maior valor; – Algarismos de menor valor à esquerda são subtraídos do algarismo de maior valor; – Nenhum símbolo pode ser repetido lado a lado por mais de 3 vezes.
  99. 99. O problema dos números romanos ● Utilizando conceitos de TDD, desenvolver um software onde dado um numeral romano, o programa deve convertê-lo para o número inteiro correspondente.
  100. 100. O problema dos números romanos ● Primeiro teste: <?php <?php require getcwd().'/n_romanos/src/ConversorDeNumeroRomano.php'; require getcwd().'/n_romanos/src/ConversorDeNumeroRomano.php'; class ConversorDeNumeroRomanoTest extends PHPUnit_Framework_TestCase {{ class ConversorDeNumeroRomanoTest extends PHPUnit_Framework_TestCase public function testDeveEntenderOSimboloI() {{ public function testDeveEntenderOSimboloI() $romano = new ConversorDeNumeroRomano(); $romano = new ConversorDeNumeroRomano(); $numero = $romano->converte("I"); $numero = $romano->converte("I"); }} ?> ?> }} $this->assertEquals(1, $numero); $this->assertEquals(1, $numero);
  101. 101. O problema dos números romanos Implementar a classe ConversorDeNumeroRomano da maneira mais simples para que o primeiro teste passe: ● <?php <?php class ConversorDeNumeroRomano {{ class ConversorDeNumeroRomano }} }} ?> ?> public function converte($numeroEmRomano) {{ public function converte($numeroEmRomano) return 1; return 1; }}
  102. 102. O problema dos números romanos Adicionando o segundo teste: ● public function testDeveEntenderOSimboloI() {{ public function testDeveEntenderOSimboloI() $romano = new ConversorDeNumeroRomano(); $romano = new ConversorDeNumeroRomano(); $numero = $romano->converte("I"); $numero = $romano->converte("I"); }} $this->assertEquals(1, $numero); $this->assertEquals(1, $numero); public function testDeveEntenderOSimboloV() {{ public function testDeveEntenderOSimboloV() $romano = new ConversorDeNumeroRomano(); $romano = new ConversorDeNumeroRomano(); $numero = $romano->converte("V"); $numero = $romano->converte("V"); }} $this->assertEquals(5, $numero); $this->assertEquals(5, $numero);
  103. 103. O problema dos números romanos ● Implementar a classe ConversorDeNumeroRomano da maneira mais simples para que os dois primeiros testes passem: <?php <?php class ConversorDeNumeroRomano {{ class ConversorDeNumeroRomano public function converte($numeroEmRomano) {{ public function converte($numeroEmRomano) if($numeroEmRomano == "I") if($numeroEmRomano == "I") return 1; return 1; else if($numeroEmRomano == "V") else if($numeroEmRomano == "V") return 5; return 5; else else return 0; return 0; }} }} ?> ?> }} }}
  104. 104. O problema dos números romanos Para não precisarmos utilizar vários ifs encadeados ou um switch case vamos armazenar todos os símbolos com seus valores em um vetor, assim contemplamos a primeira parte, que é converter os valores quando o símbolo está sozinho. ● class ConversorDeNumeroRomano {{ class ConversorDeNumeroRomano protected $converteArray; protected $converteArray; public function __construct() public function __construct() {{ $this->converteArray = array('I' => '1', 'V' => '5', 'X' => '10', $this->converteArray = array('I' => '1', 'V' => '5', 'X' => '10', 'L' => '50', 'C' => '100', 'D' => '500', 'L' => '50', 'C' => '100', 'D' => '500', 'M' => '1000'); 'M' => '1000'); }} }} public function converte($numeroEmRomano) {{ public function converte($numeroEmRomano) return $this->converteArray[$numeroEmRomano]; return $this->converteArray[$numeroEmRomano]; }}
  105. 105. O problema dos números romanos ● Adicionando o terceiro e quarto teste : ... ... public function testDeveEntenderOSimboloII() {{ public function testDeveEntenderOSimboloII() $romano = new ConversorDeNumeroRomano(); $romano = new ConversorDeNumeroRomano(); $numero = $romano->converte("II"); $numero = $romano->converte("II"); }} $this->assertEquals(2, $numero); $this->assertEquals(2, $numero); public function testDeveEntenderOSimboloIII() {{ public function testDeveEntenderOSimboloIII() $romano = new ConversorDeNumeroRomano(); $romano = new ConversorDeNumeroRomano(); $numero = $romano->converte("III"); $numero = $romano->converte("III"); }} $this->assertEquals(3, $numero); $this->assertEquals(3, $numero);
  106. 106. O problema dos números romanos ● Implementando a solução mais simples para fazer todos os testes passarem: public function converte($numeroEmRomano) {{ public function converte($numeroEmRomano) $acumulador = 0; $acumulador = 0; for($i = 0; $i < strlen($numeroEmRomano); $i++) {{ for($i = 0; $i < strlen($numeroEmRomano); $i++) $acumulador += $this->converteArray[$numeroEmRomano[$i]]; $acumulador += $this->converteArray[$numeroEmRomano[$i]]; }} return $acumulador; return $acumulador; }}
  107. 107. O problema dos números romanos ● Adicionando testes com números de menor valor a esquerda e a direita: ... ... public function testDeveEntenderOSimboloIV() {{ public function testDeveEntenderOSimboloIV() $romano = new ConversorDeNumeroRomano(); $romano = new ConversorDeNumeroRomano(); $numero = $romano->converte("IV"); $numero = $romano->converte("IV"); }} $this->assertEquals(4, $numero); $this->assertEquals(4, $numero); public function testDeveEntenderOSimboloXI() {{ public function testDeveEntenderOSimboloXI() $romano = new ConversorDeNumeroRomano(); $romano = new ConversorDeNumeroRomano(); $numero = $romano->converte("XI"); $numero = $romano->converte("XI"); }} $this->assertEquals(11, $numero); $this->assertEquals(11, $numero);
  108. 108. O problema dos números romanos ● Implementando a solução mais simples para fazer todos os testes passarem: public function converte($numeroEmRomano) {{ public function converte($numeroEmRomano) $acumulador = 0; $acumulador = 0; $ultimoVizinhoDaDireita = 0; $ultimoVizinhoDaDireita = 0; for($i = strlen($numeroEmRomano) --1; $i >= 0 ; ;$i--){ for($i = strlen($numeroEmRomano) 1; $i >= 0 $i--){ echo $numeroEmRomano[$i]; echo $numeroEmRomano[$i]; $atual = $this->converteArray[$numeroEmRomano[$i]]; $atual = $this->converteArray[$numeroEmRomano[$i]]; // se o da direita for menor, o multiplicaremos // se o da direita for menor, o multiplicaremos // por -1 para torná-lo negativo // por -1 para torná-lo negativo $multiplicador = 1; $multiplicador = 1; if($atual < $ultimoVizinhoDaDireita) $multiplicador = -1; if($atual < $ultimoVizinhoDaDireita) $multiplicador = -1; $acumulador += $atual **$multiplicador; $acumulador += $atual $multiplicador; // atualiza o vizinho da direita // atualiza o vizinho da direita $ultimoVizinhoDaDireita = $atual; $ultimoVizinhoDaDireita = $atual; }} return $acumulador; return $acumulador; }}
  109. 109. O problema dos números romanos ● Todos os testes já passam, o algoritmo criado até então já atende o cenário do teste.
  110. 110. O problema dos números romanos ● Refletindo sobre o assunto – Que vantagens temos programando assim? ● ● ● ● Foco no teste e não na implementação; Código nasce testado; Simplicidade; Melhor reflexão sobre o design da classe.
  111. 111. Brainstorming
  112. 112. Dúvidas? ● cezar08@unochapeco.edu.br ● http://www.slideshare.net/cezar08
  113. 113. Referências ● http://phpunit.de/manual (2013); ● Bergmann, PHPUnit Manual (2005); ● ● ● ● ● BECK, Kent. Test Driven Development: By Example, Addison-Wesley, 2002. BECK ,Kent. Test Driven Development: By Example. ISBN-10: 0321146530 ISBN-13: 9780321146533. Publisher: Addison-Wesley Professional Copyright: 2003, 220 p. Aniche,TDD - Teste e Design no Mundo Real (2012). KOSKELA, Lasse. Test Driven: TDD and Acceptance TDD for Java Developers. Manning Publications. 2007, 543 p. SOMMERVILLE, Ian. Engenharia de Software. 7. ed. São Paulo: Addison Wesley, 2004.

×