tdd - prática com rspec

161
Desenvolvimento Baseado em Testes RSpec - Prática Eduardo Mendes [email protected]

Upload: eduardo-mendes-de-oliveira

Post on 26-Jun-2015

903 views

Category:

Technology


1 download

DESCRIPTION

Prática de TDD baseada no livro RSpec Book. Código fonte inicial em https://github.com/dudumendes/tdd_aulas/tree/master/jogo_senha

TRANSCRIPT

Page 1: TDD - Prática com RSpec

Desenvolvimento Baseado em TestesRSpec - PráticaEduardo Mendes [email protected]

Page 2: TDD - Prática com RSpec

@dudumendes

Dicas com RSpec

Page 3: TDD - Prática com RSpec

@dudumendes

Executando spec

rspec arquivo.rb

executa um único spec

rspec path/para/meus/specs

executar todos os specs contidos no diretório

Page 4: TDD - Prática com RSpec

@dudumendes

rspec formatosFormatando para documentação

rspec path/para/meus/spec --format documentation

rspec path/para/meus/spec --format d

rspec path/para/meus/spec -f d

Gerando um arquivo html

rspec path/para/meus/spec -f html > relatorio.html

rspec path/para/meus/spec -f h > relatorio.html

Page 5: TDD - Prática com RSpec

@dudumendes

Page 6: TDD - Prática com RSpec

@dudumendes

Colorindo o resultadorspec spec --color

Page 7: TDD - Prática com RSpec

@dudumendes

TDD

Page 8: TDD - Prática com RSpec

@dudumendes

O que veremos?

Page 9: TDD - Prática com RSpec

@dudumendes

O que veremos?Iniciar os testes baseados em cenários previamente definidos

Page 10: TDD - Prática com RSpec

@dudumendes

O que veremos?Iniciar os testes baseados em cenários previamente definidos

Nunca codifique uma funcionalidade nova sem um teste falhando

Page 11: TDD - Prática com RSpec

@dudumendes

O que veremos?Iniciar os testes baseados em cenários previamente definidos

Nunca codifique uma funcionalidade nova sem um teste falhando

Utilizar 01 expectativa por exemplo

Page 12: TDD - Prática com RSpec

@dudumendes

O que veremos?Iniciar os testes baseados em cenários previamente definidos

Nunca codifique uma funcionalidade nova sem um teste falhando

Utilizar 01 expectativa por exemplo

Sempre refatorar na fase verde

Page 13: TDD - Prática com RSpec

@dudumendes

O que veremos?Iniciar os testes baseados em cenários previamente definidos

Nunca codifique uma funcionalidade nova sem um teste falhando

Utilizar 01 expectativa por exemplo

Sempre refatorar na fase verde

Buscar sempre o cenário mais simples

Page 14: TDD - Prática com RSpec

@dudumendes

O que veremos?Iniciar os testes baseados em cenários previamente definidos

Nunca codifique uma funcionalidade nova sem um teste falhando

Utilizar 01 expectativa por exemplo

Sempre refatorar na fase verde

Buscar sempre o cenário mais simples

Pequenos passos

Page 15: TDD - Prática com RSpec

@dudumendes

O que veremos?Iniciar os testes baseados em cenários previamente definidos

Nunca codifique uma funcionalidade nova sem um teste falhando

Utilizar 01 expectativa por exemplo

Sempre refatorar na fase verde

Buscar sempre o cenário mais simples

Pequenos passos

Utilizar contextos para melhor compreensão dos testes

Page 16: TDD - Prática com RSpec

@dudumendes

O que veremos?Iniciar os testes baseados em cenários previamente definidos

Nunca codifique uma funcionalidade nova sem um teste falhando

Utilizar 01 expectativa por exemplo

Sempre refatorar na fase verde

Buscar sempre o cenário mais simples

Pequenos passos

Utilizar contextos para melhor compreensão dos testes

Extrair métodos para tornar código mais claro

Page 17: TDD - Prática com RSpec

@dudumendes

O que veremos?Iniciar os testes baseados em cenários previamente definidos

Nunca codifique uma funcionalidade nova sem um teste falhando

Utilizar 01 expectativa por exemplo

Sempre refatorar na fase verde

Buscar sempre o cenário mais simples

Pequenos passos

Utilizar contextos para melhor compreensão dos testes

Extrair métodos para tornar código mais claro

Adicionar complexidade gradativamente

Page 18: TDD - Prática com RSpec

@dudumendes

TDD com RSpec

Page 19: TDD - Prática com RSpec

@dudumendes

IntroduçãoConstrução de um Jogo chamado Senha

Estrutura inicial disponibilizada no Github https://github.com/dudumendes/tdd_aulas/tree/master/jogo_senha

Specs separados dos fontes

Classes com nomes qualificados

Page 20: TDD - Prática com RSpec

Jogo SenhaUm Jogo que gera uma senha de 04 posições com os algarismos 1, 2, 3, 4 !O jogador tenta adivinhar a senha através de uma contra-senha !O Jogo é capaz de avaliar a contra-senha

Page 21: TDD - Prática com RSpec

@dudumendes

Jogo Senha

Uma contra-senha é avaliada através dos seguintes sinais e regras:

+ : um sinal de “positivo” é apresentado para cada valor correto na posição correta

- : um único sinal de “negativo” é apresentado para cada valor correto na posição errada

!

Precedência dos sinais: + > -

Page 22: TDD - Prática com RSpec

@dudumendes

Jogo SenhaExemplos de avaliação para a Senha: 1232

Contra-senha Avaliação1232 Parabens, fulano voce quebrou a senha!44442321143242321322

Page 23: TDD - Prática com RSpec

@dudumendes

Senha - estrutura

Page 24: TDD - Prática com RSpec

@dudumendes

github.com/dudumendes/tdd_aulas/ jogo_senha

Page 25: TDD - Prática com RSpec

@dudumendes

Funcionalidade: iniciar jogo Cenário 1 - Iniciar o jogo

Cenário: iniciar o jogo

Dado que eu ainda não estou jogando

Quando eu vir “Bem-vindo ao Senha”

Então eu espero ver “Informe jogador:”

Page 26: TDD - Prática com RSpec

@dudumendes

Page 27: TDD - Prática com RSpec

@dudumendes

“Nunca codifique uma funcionalidade nova

sem um teste falhando”

Page 28: TDD - Prática com RSpec

@dudumendes

O ciclo básico do TDD

Escrever um teste unitário

que falha

Fazer um código passar no teste

Refatorar

Page 29: TDD - Prática com RSpec

@dudumendes

require 'spec_helper' !module Senha describe Jogo do describe "#iniciar" do it "envia uma mensagem de boas-vindas" it "solicita pelo 1.o jogador" end end end

spec/senha/jogo_spec.rb

Page 30: TDD - Prática com RSpec

@dudumendes

module Senha class Jogo end end

lib/senha/jogo.rb

Page 31: TDD - Prática com RSpec

@dudumendes

executando o RSpec

Page 32: TDD - Prática com RSpec

@dudumendes

Adicionando algo

Page 33: TDD - Prática com RSpec

@dudumendes

Adicionando algo

O jogo será jogado no terminal

Page 34: TDD - Prática com RSpec

@dudumendes

Adicionando algo

O jogo será jogado no terminal

O jogo enviará mensagens para uma saída [output]

Page 35: TDD - Prática com RSpec

@dudumendes

Adicionando algo

O jogo será jogado no terminal

O jogo enviará mensagens para uma saída [output]

boas-vindas

Page 36: TDD - Prática com RSpec

@dudumendes

Adicionando algo

O jogo será jogado no terminal

O jogo enviará mensagens para uma saída [output]

boas-vindas

retornos sobre as tentativas de adivinhar a senha

Page 37: TDD - Prática com RSpec

@dudumendes

Adicionando algo

O jogo será jogado no terminal

O jogo enviará mensagens para uma saída [output]

boas-vindas

retornos sobre as tentativas de adivinhar a senha

nosso output será um dublê

Page 38: TDD - Prática com RSpec

@dudumendes

Adicionando algo

O jogo será jogado no terminal

O jogo enviará mensagens para uma saída [output]

boas-vindas

retornos sobre as tentativas de adivinhar a senha

nosso output será um dublê

faremos expectativas sobre este comportamento

Page 39: TDD - Prática com RSpec

@dudumendes

require 'spec_helper' !module Senha describe Jogo do describe "#iniciar" do it "envia uma mensagem de boas-vindas" do output = double('output') ! jogo = Jogo.new(output) output.should_receive(:puts).with("Bem-vindo ao Senha") ! jogo.iniciar end it "solicita pelo 1.o jogador"

end end end

Page 40: TDD - Prática com RSpec

@dudumendes

rspec spec -c -f -d

Page 41: TDD - Prática com RSpec

@dudumendes

module Senha class Jogo def initialize(output) @output = output end def iniciar end end end

Page 42: TDD - Prática com RSpec

@dudumendes

Page 43: TDD - Prática com RSpec

@dudumendes

module Senha class Jogo def initialize(output) @output = output end def iniciar @output.puts 'Bem-vindo ao Senha' end end end

Page 44: TDD - Prática com RSpec

@dudumendes

Page 45: TDD - Prática com RSpec

@dudumendes

Resolva a pendência

Resposta no próximo slide

Page 46: TDD - Prática com RSpec

@dudumendes

it "solicita pelo 1.o jogador" do output = double('output') jogo = Jogo.new(output) output.should_receive(:puts).with("Informe jogador:") jogo.iniciar end

Page 47: TDD - Prática com RSpec

@dudumendes

Page 48: TDD - Prática com RSpec

@dudumendes

module Senha class Jogo def initialize(output) @output = output end def iniciar @output.puts 'Bem-vindo ao Senha' @output.puts 'Informe jogador:' end end end

Page 49: TDD - Prática com RSpec

@dudumendes

Page 50: TDD - Prática com RSpec

@dudumendes

02 exemplos falhandoOs doubles reagem exatamente da maneira como foram programados

1.º exemplo

“Bem-vindo ao Senha” e somente isso

2.º exemplo

“Informe jogador:” e somente isso

Possível solução

combinar as 02 coisas em um único exemplo

Page 51: TDD - Prática com RSpec

@dudumendes

Page 52: TDD - Prática com RSpec

@dudumendes

“01 expectativa por exemplo”

Page 53: TDD - Prática com RSpec

@dudumendes

“01 expectativa por exemplo”Se 02 expectativas falharem, só veremos a 1.ª

Page 54: TDD - Prática com RSpec

@dudumendes

02 expectativas em um 1 exemplo

Se ambas expectativas falharem, só veremos a 1.ª

01 expectativa por exemplo

Veremos ambas falharem

01 expectativa por exemplo

Page 55: TDD - Prática com RSpec

@dudumendes

método as_null_object

Informa ao double para responder somente às mensagens configuradas nas expectativas

as outras são ignoradas

baseado no padrão Null Object

Page 56: TDD - Prática com RSpec

@dudumendes!module Senha describe Jogo do describe "#iniciar" do it "envia uma mensagem de boas-vindas" do output = double('output').as_null_object jogo = Jogo.new(output) ! output.should_receive(:puts).with("Bem-vindo ao Senha") jogo.iniciar end ! it "solicita pelo 1.o jogador" do output = double('output').as_null_object jogo = Jogo.new(output) output.should_receive(:puts).with("Informe jogador:") jogo.iniciar end end end end

Page 57: TDD - Prática com RSpec

@dudumendes

Page 58: TDD - Prática com RSpec

@dudumendes

O ciclo básico do TDD

Escrever um teste unitário

que falha

Fazer um código passar no teste

Refatorar

Page 59: TDD - Prática com RSpec

@dudumendes

Refatorando“Refatoração é o processo de mudança de um sistema de software de tal forma que não se altere o comportamento externo do código e ainda melhore a sua estrutura interna”

Martin Fowler

Se alguma mudança fizé-lo falhar, é porque foi ela quem causou o problema

É possível retornar para o verde novamente

Page 60: TDD - Prática com RSpec

@dudumendes

Page 61: TDD - Prática com RSpec

@dudumendes

Refatorar na fase verde

Page 62: TDD - Prática com RSpec

@dudumendes

Refatorar na fase verdeRefatorar com confiança

Page 63: TDD - Prática com RSpec

@dudumendes

Refatorando

Buscar duplicações

na implementação

e nos exemplos

Page 64: TDD - Prática com RSpec

@dudumendes!module Senha describe Jogo do describe "#iniciar" do it "envia uma mensagem de boas-vindas" do output = double('output').as_null_object jogo = Jogo.new(output) ! output.should_receive(:puts).with("Bem-vindo ao Senha") jogo.iniciar end ! it "solicita pelo 1.o jogador" do output = double('output').as_null_object jogo = Jogo.new(output) output.should_receive(:puts).with("Informe jogador:") jogo.iniciar end end end end

Page 65: TDD - Prática com RSpec

@dudumendes

Crie o before

Page 66: TDD - Prática com RSpec

@dudumendes

before(:each) do @output = double('output').as_null_object @jogo = Jogo.new(@output) end ! it "envia uma mensagem de boas-vindas" do @output.should_receive(:puts).with("Bem-vindo ao Senha") @jogo.iniciar end ! it "solicita pelo 1.o jogador" do @output.should_receive(:puts).with("Informe jogador:") @jogo.iniciar end

Page 67: TDD - Prática com RSpec

@dudumendes

método let evitando os @

Se o bloco before é só para criar variáveis de instâncias com valores

utilize o let

!

let(:output) {double(‘output’).as_null_object }

Page 68: TDD - Prática com RSpec

@dudumendes

describe Jogo do describe "#iniciar" do let(:output) { double('output').as_null_object } let(:jogo) { Jogo.new(output) } it "envia uma mensagem de boas-vindas" do output.should_receive(:puts).with("Bem-vindo ao Senha") jogo.iniciar end ! it "solicita pelo 1.o jogador" do output.should_receive(:puts).with("Informe jogador:") jogo.iniciar end end end

Page 69: TDD - Prática com RSpec

@dudumendes

Funcionalidade o jogador submete uma contra-senha

O jogador submete uma contra-senha de 04 dígitos.

O jogo avalia a contra senha com sinais + e -

Para cada dígito na contra-senha que casa com um dígito na posição correta

a avaliação inclui um sinal de +

Para cada dígito na contra-senha que casa com um dígito, mas não na posição

a avaliação inclui um sinal de -

Page 70: TDD - Prática com RSpec

@dudumendes

Esquema do Cenário: o jogador informa a contra-senha

Dado que a senha é “<senha>”

Quando eu informar uma “<contra-senha>”

Então a avaliação deve ser “<avaliação>”

Page 71: TDD - Prática com RSpec

@dudumendes

Cenáriossem acertos

!

!

com 01 dígito correto

!

!

com 2 dígitos corretos

!

com 03 dígitos corretos

!

!

!

com todos corretos

senha contra-senha avaliacao

1234 5555

senha contra-senha avaliacao1234 1555 +1234 2555 -

senha contra-senha avaliacao1234 5254 ++1234 5154 +-1234 2545 --

senha contra-senha avaliacao1234 5234 +++1234 5134 ++-1234 5124 +--1234 5123 ---

senha contra-senha avaliacao1234 1234 ++++1234 1243 ++--1234 1423 +---1234 4321 ----

Page 72: TDD - Prática com RSpec

@dudumendes

Criação da senha

Vamos informar a senha na hora da chamada ao início do jogo

Page 73: TDD - Prática com RSpec

@dudumendes

it "envia uma mensagem de boas-vindas" do output.should_receive(:puts).with("Bem-vindo ao Senha") jogo.iniciar('1234') end !it "solicita pelo 1.o jogador" do ! output.should_receive(:puts).with("Informe jogador:") jogo.iniciar('1234') !end !

Page 74: TDD - Prática com RSpec

@dudumendes

Page 75: TDD - Prática com RSpec

@dudumendes

module Senha class Jogo def initialize(output) @output = output end def iniciar(senha) @output.puts 'Bem-vindo ao Senha' @output.puts 'Informe jogador:' end end end

Page 76: TDD - Prática com RSpec

@dudumendes

Avaliação

Page 77: TDD - Prática com RSpec

@dudumendes

14 cenários identificados

Qual deles é o mais importante?

Por qual cenário começar?

Page 78: TDD - Prática com RSpec

@dudumendes

Page 79: TDD - Prática com RSpec

@dudumendes

“Utilize o cenário mais simples”

Page 80: TDD - Prática com RSpec

@dudumendes

“Utilize o cenário mais simples”Que permita progredir facilmente

Page 81: TDD - Prática com RSpec

@dudumendes

“Utilize o cenário mais simples”Que permita progredir facilmente

Pequenos passos

Page 82: TDD - Prática com RSpec

@dudumendes

Cenáriossem acertos

!

!

com 01 dígito correto

!

!

com 2 dígitos corretos

!

com 03 dígitos corretos

!

!

!

com todos corretos

senha contra-senha

avaliacao

1234 5555

senha contra-senha avaliacao1234 1555 +1234 2555 -

senha contra-senha avaliacao1234 5254 ++1234 5154 +-1234 2545 --

senha contra-senha avaliacao1234 5234 +++1234 5134 ++-1234 5124 +--1234 5123 ---

senha contra-senha avaliacao1234 1234 ++++1234 1243 ++--1234 1423 +---1234 4321 ----

Page 83: TDD - Prática com RSpec

@dudumendes

describe "#avaliar" do it "envia ‘’ quando receber ‘5555’" do end end

Page 84: TDD - Prática com RSpec

@dudumendes

Page 85: TDD - Prática com RSpec

@dudumendes

“Utilize contextos”

Page 86: TDD - Prática com RSpec

@dudumendes

“Utilize contextos”organizam seus testes

Page 87: TDD - Prática com RSpec

@dudumendes

“Utilize contextos”organizam seus testes

tornam-os mais compreensíveis

Page 88: TDD - Prática com RSpec

@dudumendes

describe "#avaliar" do ! context "sem acertos" do ! it "envia uma avaliacao com ''" do jogo.iniciar('1234') output.should_receive(:puts).with('') jogo.avaliar('5555') end ! end ! end

Page 89: TDD - Prática com RSpec

@dudumendes

Page 90: TDD - Prática com RSpec

@dudumendes

module Senha class Jogo def initialize(output) @output = output end def iniciar(senha) @output.puts 'Bem-vindo ao Senha' @output.puts 'Informe jogador:' end def avaliar(contra_senha) end end end

Page 91: TDD - Prática com RSpec

@dudumendes

Page 92: TDD - Prática com RSpec

@dudumendes

Qual a solução mais simples?

Page 93: TDD - Prática com RSpec

@dudumendes

module Senha class Jogo def initialize(output) @output = output end def iniciar(senha) @output.puts 'Bem-vindo ao Senha' @output.puts 'Informe jogador:' end def avaliar(contra_senha) @output.puts '' end end end

Page 94: TDD - Prática com RSpec

@dudumendes

Page 95: TDD - Prática com RSpec

@dudumendes

Próximo cenário?sem acertos

!

!

com 01 dígito correto

!

!

com 2 dígitos corretos

!

com 03 dígitos corretos

!

!

!

com todos corretos

senha contra-senha

avaliacao

1234 5555

senha contra-senha avaliacao1234 1555 +1234 2555 -

senha contra-senha avaliacao1234 5254 ++1234 5154 +-1234 2545 --

senha contra-senha avaliacao1234 5234 +++1234 5134 ++-1234 5124 +--1234 5123 ---

senha contra-senha avaliacao1234 1234 ++++1234 1243 ++--1234 1423 +---1234 4321 ----

Page 96: TDD - Prática com RSpec

@dudumendes

context "com 01 digito correto" do it "envia uma avaliacao com '-'" do jogo.iniciar('1234') output.should_receive(:puts).with('-') jogo.avaliar('2555') end end

Page 97: TDD - Prática com RSpec

@dudumendes

Page 98: TDD - Prática com RSpec

@dudumendesmodule Senha class Jogo def initialize(output) @output = output end def iniciar(senha) @senha = senha @output.puts 'Bem-vindo ao Senha' @output.puts 'Informe jogador:' end def avaliar(contra_senha) if @senha.include?(contra_senha[0]) @output.puts '-' else @output.puts '' end end end end

Page 99: TDD - Prática com RSpec

@dudumendes

Page 100: TDD - Prática com RSpec

@dudumendes

O ciclo básico do TDD

Escrever um teste unitário

que falha

Fazer um código passar no teste

Refatorar para remover

duplicação

Page 101: TDD - Prática com RSpec

@dudumendesmodule Senha class Jogo def initialize(output) @output = output end def iniciar(senha) @senha = senha @output.puts 'Bem-vindo ao Senha' @output.puts 'Informe jogador:' end def avaliar(contra_senha) if @senha.include?(contra_senha[0]) @output.puts '-' else @output.puts '' end end end end

Page 102: TDD - Prática com RSpec

@dudumendesmodule Senha class Jogo def initialize(output) @output = output end def iniciar(senha) @senha = senha @output.puts 'Bem-vindo ao Senha' @output.puts 'Informe jogador:' end def avaliar(contra_senha) if @senha.include?(contra_senha[0]) avalicao = '-' else avaliacao = '' end @output.puts avaliacao end end end

Page 103: TDD - Prática com RSpec

@dudumendes

Próximo cenário?sem acertos

!

!

com 01 dígito correto

!

!

com 2 dígitos corretos

!

com 03 dígitos corretos

!

!

!

com todos corretos

senha contra-senha

avaliacao

1234 5555

senha contra-senha avaliacao1234 1555 +1234 2555 -

senha contra-senha avaliacao1234 5254 ++1234 5154 +-1234 2545 --

senha contra-senha avaliacao1234 5234 +++1234 5134 ++-1234 5124 +--1234 5123 ---

senha contra-senha avaliacao1234 1234 ++++1234 1243 ++--1234 1423 +---1234 4321 ----

Page 104: TDD - Prática com RSpec

@dudumendes

context "com 01 digito exatamente correto" do it "envia uma avaliacao com '+'" do jogo.iniciar('1234') output.should_receive(:puts).with('+') jogo.avaliar('1555') end end

Page 105: TDD - Prática com RSpec

@dudumendes

Page 106: TDD - Prática com RSpec

@dudumendes

def avaliar(contra_senha) if @senha[0] == contra_senha[0] avaliacao = '+' elsif @senha.include?(contra_senha[0]) avaliacao = '-' else avaliacao = '' end @output.puts avaliacao end

Page 107: TDD - Prática com RSpec

@dudumendes

Page 108: TDD - Prática com RSpec

@dudumendes

O ciclo básico do TDD

Escrever um teste unitário

que falha

Fazer um código passar no teste

Refatorar para expressar

intenção

Page 109: TDD - Prática com RSpec

@dudumendes

Refatorar para expressar intenção

À medida que o projeto vai evoluindo

aparecem novas duplicações

Remover duplicação

melhorar o projeto

dar mais semântica ao código

Page 110: TDD - Prática com RSpec

@dudumendes

def avaliar(contra_senha) if @senha[0] == contra_senha[0] avaliacao = '+' elsif @senha.include?(contra_senha[0]) avaliacao = '-' else avaliacao = '' end @output.puts avaliacao end

As intenções estão claras?

Page 111: TDD - Prática com RSpec

@dudumendes

Page 112: TDD - Prática com RSpec

@dudumendes

“Extraia métodos”

Page 113: TDD - Prática com RSpec

@dudumendes

“Extraia métodos”elimina duplicação

Page 114: TDD - Prática com RSpec

@dudumendes

“Extraia métodos”elimina duplicação

introduz abstrações que expressam com mais clareza

a intenção do código

Page 115: TDD - Prática com RSpec

@dudumendes

Extrair Método

Page 116: TDD - Prática com RSpec

@dudumendes

Extrair Método• Contexto

• métodos muito longos

• lógicas de complexo entendimento

Page 117: TDD - Prática com RSpec

@dudumendes

Extrair Método• Contexto

• métodos muito longos

• lógicas de complexo entendimento

• Solução

• fracionar o método em métodos menores mais coesos

Page 118: TDD - Prática com RSpec

@dudumendes

Extrair Método• Contexto

• métodos muito longos

• lógicas de complexo entendimento

• Solução

• fracionar o método em métodos menores mais coesos

• Extração de comportamentos para novos métodos

Page 119: TDD - Prática com RSpec

@dudumendes

def init content_pane.layout(FlowLayout.new) movie_list = List.new(my_editor.movies) scroller = ScrollPane.new(movie_list) content_pane.add(scroller) movie_field = TextField.new(16) content_pane.add(movie_field) add_button = Button.new(“Add") .... end

Page 120: TDD - Prática com RSpec

@dudumendes

def init // set the layout content_pane.layout(FlowLayout.new) ! // create the list movie_list = List.new(my_editor.movies) scroller = ScrollPane.new(movie_list) content_pane.add(scroller) ! // create the field movie_field = TextField.new(16) content_pane.add(movie_field) ! // create theadd button add_button = Button.new(“Add") .... end

Page 121: TDD - Prática com RSpec

@dudumendes

def init setLayout initMovieList initMovieField initAddButton end def setLayout contentPane.layout(FlowLayout.new) end def initMovieList movie_list = List.new(my_editor.movies) scroller = ScrollPane.new(movie_list) content_pane.add(scroller) end def initMovieField movie_field = TextField.new(16) content_pane.add(movie_field) end def initAddButton addButton = Button.new(“Add") addButton.addActionListener(ActionListener()) {

Page 122: TDD - Prática com RSpec

@dudumendes

Extrair Método outro caso

Se um trecho de código duplicado diferentes do programa

Classe1

Page 123: TDD - Prática com RSpec

@dudumendes

Extrair Método outro caso

• Se as duplicatas de código devem permanecer sempre iguais, ou seja, uma vez que se realize uma alteração em uma delas, as demais devem refletir a alteração

Classe1

Page 124: TDD - Prática com RSpec

@dudumendes

Extrair Método outro caso

• Se as duplicatas de código devem permanecer sempre iguais, ou seja, uma vez que se realize uma alteração em uma delas, as demais devem refletir a alteração

Classe1

Page 125: TDD - Prática com RSpec

@dudumendes

def edit id = params[:id] @personagem = Personagem.find(id) //Mais código end !def create id = params[:id] @personagem = Personagem.find(id) //Mais código end

Page 126: TDD - Prática com RSpec

@dudumendes

Extraindo o método• Concentre o código que se repete em um único

lugar, por exemplo, em um método e leve as dependências para lá

Page 127: TDD - Prática com RSpec

@dudumendes

Extraindo o método• Concentre o código que se repete em um único

lugar, por exemplo, em um método e leve as dependências para lá

def edit id = params[:id] @personagem = Personagem.find(id) //Mais código end

Page 128: TDD - Prática com RSpec

@dudumendes

Extraindo o método• Concentre o código que se repete em um único

lugar, por exemplo, em um método e leve as dependências para lá

def edit id = params[:id] @personagem = Personagem.find(id) //Mais código end

def novo_metodo id = params[:id] @personagem = Personagem.find(id) //Mais código end

Page 129: TDD - Prática com RSpec

@dudumendes

def edit self.novo_metodo end !!def create self.novo_metodo end !!def novo_metodo id = params[:id] @personagem = Personagem.find(id) //Mais código end

Page 130: TDD - Prática com RSpec

@dudumendes

Extração de método no Senha

Page 131: TDD - Prática com RSpec

@dudumendes

def avaliar(contra_senha) if digito_exato?(contra_senha, 0) avaliacao = '+' ! elsif digito_correto?(contra_senha, 0) avaliacao = '-' ! else avaliacao = '' end @output.puts avaliacao ! end def digito_exato?(contra_senha, index) @senha[index] == contra_senha[index] end def digito_correto?(contra_senha, index) @senha.include?(contra_senha[index]) end

Page 132: TDD - Prática com RSpec

@dudumendes

Page 133: TDD - Prática com RSpec

@dudumendes

Page 134: TDD - Prática com RSpec

@dudumendes

“Adicione complexidade gradativamente”

Page 135: TDD - Prática com RSpec

@dudumendes

“Adicione complexidade gradativamente”

confiança ao programar

Page 136: TDD - Prática com RSpec

@dudumendes

Próximo cenário?sem acertos

!

!

com 01 dígito correto

!

!

com 2 dígitos corretos

!

com 03 dígitos corretos

!

!

!

com todos corretos

senha contra-senha

avaliacao

1234 5555

senha contra-senha avaliacao1234 1555 +1234 2555 -

senha contra-senha avaliacao1234 5254 ++1234 5154 +-1234 2545 --

senha contra-senha avaliacao1234 5234 +++1234 5134 ++-1234 5124 +--1234 5123 ---

senha contra-senha avaliacao1234 1234 ++++1234 1243 ++--1234 1423 +---1234 4321 ----

Page 137: TDD - Prática com RSpec

@dudumendes

! context "com 02 digitos corretos" do it "envia uma avaliacao com '--'" do jogo.iniciar('1234') output.should_receive(:puts).with('--') jogo.avaliar('2355') end end

Page 138: TDD - Prática com RSpec

@dudumendes

Page 139: TDD - Prática com RSpec

@dudumendes

Obtendo resultado

Como já foram realizadas algumas refatorações

o código já passa a nos ajudar

Page 140: TDD - Prática com RSpec

@dudumendes

def avaliar(contra_senha) avaliacao = '' (0..3).each do |index| ! if digito_exato?(contra_senha, index) avaliacao << '+' ! elsif digito_correto?(contra_senha, index) avaliacao << '-' ! end ! end @output.puts avaliacao end

Page 141: TDD - Prática com RSpec

@dudumendes

Page 142: TDD - Prática com RSpec

@dudumendes

Próximo cenário?sem acertos

!

!

com 01 dígito correto

!

!

com 2 dígitos corretos

!

com 03 dígitos corretos

!

!

!

com todos corretos

senha contra-senha

avaliacao

1234 5555

senha contra-senha avaliacao1234 1555 +1234 2555 -

senha contra-senha avaliacao1234 5254 ++1234 5154 +-1234 2545 --

senha contra-senha avaliacao1234 5234 +++1234 5134 ++-1234 5124 +--1234 5123 ---

senha contra-senha avaliacao1234 1234 ++++1234 1243 ++--1234 1423 +---1234 4321 ----

Page 143: TDD - Prática com RSpec

@dudumendes

context "com 01 digito correto e 01 digito exato (nesta ordem)" do it "envia uma avaliacao com '+-'" do jogo.iniciar('1234') output.should_receive(:puts).with('+-') jogo.avaliar('2535') end end

Page 144: TDD - Prática com RSpec

@dudumendes

Page 145: TDD - Prática com RSpec

@dudumendes

def avaliar(contra_senha) avaliacao = '' (0..3).each do |index| if digito_exato?(contra_senha, index) avaliacao << '+' end end (0..3).each do |index| if digito_correto?(contra_senha, index) avaliacao << '-' end end @output.puts avaliacao end

Page 146: TDD - Prática com RSpec

@dudumendes

Page 147: TDD - Prática com RSpec

@dudumendes

def digito_correto?(contra_senha, index) @senha.include?(contra_senha[index]) && !digito_exato?(contra_senha, index) end

Page 148: TDD - Prática com RSpec

@dudumendes

Page 149: TDD - Prática com RSpec

@dudumendes

Em seguida?

Page 150: TDD - Prática com RSpec

@dudumendes

Em seguida

Remover bad smells

Variáveis temporárias

Métodos longos estruturados

Classes com responsabilidades demais

Extrair classe

Page 151: TDD - Prática com RSpec

@dudumendes

O que vimos?

Page 152: TDD - Prática com RSpec

@dudumendes

O que vimos?Iniciar os testes baseados em cenários previamente

Page 153: TDD - Prática com RSpec

@dudumendes

O que vimos?Iniciar os testes baseados em cenários previamente

Nunca codifique uma funcionalidade nova sem um teste falhando

Page 154: TDD - Prática com RSpec

@dudumendes

O que vimos?Iniciar os testes baseados em cenários previamente

Nunca codifique uma funcionalidade nova sem um teste falhando

01 expectativa por exemplo

Page 155: TDD - Prática com RSpec

@dudumendes

O que vimos?Iniciar os testes baseados em cenários previamente

Nunca codifique uma funcionalidade nova sem um teste falhando

01 expectativa por exemplo

Refatorar na fase verde

Page 156: TDD - Prática com RSpec

@dudumendes

O que vimos?Iniciar os testes baseados em cenários previamente

Nunca codifique uma funcionalidade nova sem um teste falhando

01 expectativa por exemplo

Refatorar na fase verde

Utilizar o cenário mais simples

Page 157: TDD - Prática com RSpec

@dudumendes

O que vimos?Iniciar os testes baseados em cenários previamente

Nunca codifique uma funcionalidade nova sem um teste falhando

01 expectativa por exemplo

Refatorar na fase verde

Utilizar o cenário mais simples

Pequenos passos

Page 158: TDD - Prática com RSpec

@dudumendes

O que vimos?Iniciar os testes baseados em cenários previamente

Nunca codifique uma funcionalidade nova sem um teste falhando

01 expectativa por exemplo

Refatorar na fase verde

Utilizar o cenário mais simples

Pequenos passos

Utilizar contextos

Page 159: TDD - Prática com RSpec

@dudumendes

O que vimos?Iniciar os testes baseados em cenários previamente

Nunca codifique uma funcionalidade nova sem um teste falhando

01 expectativa por exemplo

Refatorar na fase verde

Utilizar o cenário mais simples

Pequenos passos

Utilizar contextos

Extrair métodos para tornar código mais claro

Page 160: TDD - Prática com RSpec

@dudumendes

O que vimos?Iniciar os testes baseados em cenários previamente

Nunca codifique uma funcionalidade nova sem um teste falhando

01 expectativa por exemplo

Refatorar na fase verde

Utilizar o cenário mais simples

Pequenos passos

Utilizar contextos

Extrair métodos para tornar código mais claro

Adicionar complexidade gradativamente

Page 161: TDD - Prática com RSpec

@dudumendes

Bibliografia

FOWLER, Martin. “Mocks aren’t Stubs”.

FOWLER, Martin; BECK, Kent; BRANT, John; Opdyke, William; ROBERTS, Don. Refactoring: Improving The Design of Existing Code.

CHELIMSKY, David. The RSpec Book. PragBook, 2011.