Desenvolvimento
Baseado em Testes
RSpec - Prática
Eduardo Mendes
edumendes@gmail.com
@dudumendes

Dicas 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
@dudumendes

rspec formatos
Formatando 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
@dudumendes
@dudumendes

Colorindo o resultado
rspec spec --color
@dudumendes

TDD
@dudumendes

O que veremos?
@dudumendes

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

O que veremos?
Iniciar os testes baseados em cenários previamente definidos
Nunca codifique uma funcionalidade nova sem um teste falhando
@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
@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
@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
@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
@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
@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
@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
@dudumendes

TDD com RSpec
@dudumendes

Introdução
Construçã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
Jogo Senha
Um 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 contrasenha
@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: + > -
@dudumendes

Jogo Senha
Exemplos de avaliação para a Senha: 1232
Contra-senha

Avaliação

1232

Parabens, fulano voce quebrou a senha!

4444
2321
1432
4232
1322
@dudumendes

Senha - estrutura
@dudumendes

github.com/dudumendes/tdd_aulas/
jogo_senha
@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:”
@dudumendes
@dudumendes

“Nunca codifique uma
funcionalidade nova
sem um teste falhando”
@dudumendes

O ciclo básico do TDD
Escrever um
teste unitário
que falha

Fazer um código
passar no teste

Refatorar
@dudumendes

spec/senha/jogo_spec.rb
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
@dudumendes

lib/senha/jogo.rb
module Senha
class Jogo
end
end
@dudumendes

executando o RSpec
@dudumendes

Adicionando algo
@dudumendes

Adicionando algo
O jogo será jogado no terminal
@dudumendes

Adicionando algo
O jogo será jogado no terminal
O jogo enviará mensagens para uma saída [output]
@dudumendes

Adicionando algo
O jogo será jogado no terminal
O jogo enviará mensagens para uma saída [output]
boas-vindas
@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
@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ê
@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
@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
rspec spec -c -f -d

@dudumendes
@dudumendes

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

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

Resolva a pendência
Resposta no próximo slide
@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
@dudumendes
@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
@dudumendes
@dudumendes

02 exemplos falhando
Os 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
@dudumendes
@dudumendes

“01 expectativa por exemplo”
@dudumendes

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

01 expectativa por exemplo
02 expectativas em um 1 exemplo
Se ambas expectativas falharem, só veremos a 1.ª
01 expectativa por exemplo
Veremos ambas falharem
@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
@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
@dudumendes
@dudumendes

O ciclo básico do TDD
Escrever um
teste unitário
que falha

Fazer um código
passar no teste

Refatorar
@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
@dudumendes
@dudumendes

Refatorar na fase verde
@dudumendes

Refatorar na fase verde
Refatorar com confiança
@dudumendes

Refatorando

Buscar duplicações
na implementação
e nos exemplos
@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
@dudumendes

Crie o before
@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
@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 }
@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
@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 -
@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>”
@dudumendes

Cenários
sem acertos

senha
!
1234
!

contra-senha

com 03 dígitos corretos
avaliacao

5555

com 01 dígito correto
senha
!
1234
!
1234

avaliacao

contra-senha

1555

+

2555

-

senha
!1234

contra-senha

avaliacao

5234

+++

1234
!
1234

5134

++-

5124

+--

!1234

5123

---

com todos corretos
senha

com 2 dígitos corretos
senha
!
1234

contra-senha

avaliacao

5254

++

1234

5154

+-

1234

2545

--

contra-senha

avaliacao

1234

1234

++++

1234

1243

++--

1234

1423

+---

1234

4321

----
@dudumendes

Criação da senha

Vamos informar a senha na hora da chamada ao início
do jogo
@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
!
@dudumendes
@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
@dudumendes

Avaliação
@dudumendes

14 cenários identificados

Qual deles é o mais importante?
Por qual cenário começar?
@dudumendes
@dudumendes

“Utilize o cenário mais simples”
@dudumendes

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

“Utilize o cenário mais simples”
Que permita progredir facilmente
Pequenos passos
@dudumendes

Cenários
sem acertos

senha
!
1234
!

contrasenha
5555

com 03 dígitos corretos
avaliacao

com 01 dígito correto
senha
!
1234
!
1234

avaliacao

contra-senha

1555

+

2555

-

senha
!1234

contra-senha

avaliacao

5234

+++

1234
!
1234

5134

++-

5124

+--

!1234

5123

---

com todos corretos
senha

com 2 dígitos corretos
senha
!
1234

contra-senha

avaliacao

5254

++

1234

5154

+-

1234

2545

--

contra-senha

avaliacao

1234

1234

++++

1234

1243

++--

1234

1423

+---

1234

4321

----
@dudumendes

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

“Utilize contextos”
@dudumendes

“Utilize contextos”
organizam seus testes
@dudumendes

“Utilize contextos”
organizam seus testes
tornam-os mais compreensíveis
@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
@dudumendes
@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
@dudumendes
@dudumendes

Qual a solução mais simples?
@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
@dudumendes
@dudumendes

Próximo cenário?
sem acertos

senha
!
1234
!

com 03 dígitos corretos

contrasenha
5555

avaliacao

com 01 dígito correto
senha
!
1234
!
1234

avaliacao

contra-senha

1555

+

2555

-

senha
!1234

contra-senha

avaliacao

5234

+++

1234
!
1234

5134

++-

5124

+--

!1234

5123

---

com todos corretos
senha

com 2 dígitos corretos
senha
!
1234

contra-senha

avaliacao

5254

++

1234

5154

+-

1234

2545

--

contra-senha

avaliacao

1234

1234

++++

1234

1243

++--

1234

1423

+---

1234

4321

----
@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
@dudumendes
module 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

@dudumendes
@dudumendes
@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
module 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

@dudumendes
module 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

@dudumendes
@dudumendes

Próximo cenário?
sem acertos

senha
!
1234
!

com 03 dígitos corretos

contrasenha
5555

avaliacao

com 01 dígito correto
senha
!
1234
!
1234

avaliacao

contra-senha

1555

+

2555

-

senha
!1234

contra-senha

avaliacao

5234

+++

1234
!
1234

5134

++-

5124

+--

!1234

5123

---

com todos corretos
senha

com 2 dígitos corretos
senha
!
1234

contra-senha

avaliacao

5254

++

1234

5154

+-

1234

2545

--

contra-senha

avaliacao

1234

1234

++++

1234

1243

++--

1234

1423

+---

1234

4321

----
@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
@dudumendes
@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
@dudumendes
@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
@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
@dudumendes

As intenções estão claras?
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
@dudumendes
@dudumendes

“Extraia métodos”
@dudumendes

“Extraia métodos”
elimina duplicação
@dudumendes

“Extraia métodos”
elimina duplicação
introduz abstrações que expressam

com mais clareza

a intenção do código
@dudumendes

Extrair Método
@dudumendes

Extrair Método
• Contexto
• métodos muito longos
• lógicas de complexo entendimento
@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
@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
@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
@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
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()) {

@dudumendes
@dudumendes

Extrair Método
outro caso
Se um trecho de código duplicado diferentes do
programa
Classe1
@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
@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
@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
@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á
@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
@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
@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
@dudumendes

Extração de método no Senha
@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
@dudumendes
@dudumendes
@dudumendes

“Adicione complexidade
gradativamente”
@dudumendes

“Adicione complexidade
gradativamente”
confiança ao programar
@dudumendes

Próximo cenário?
sem acertos

senha
!
1234
!

com 03 dígitos corretos

contrasenha
5555

avaliacao

com 01 dígito correto
senha
!
1234
!
1234

avaliacao

contra-senha

1555

+

2555

-

senha
!1234

contra-senha

avaliacao

5234

+++

1234
!
1234

5134

++-

5124

+--

!1234

5123

---

com todos corretos
senha

com 2 dígitos corretos
senha
!
1234

contra-senha

avaliacao

5254

++

1234

5154

+-

1234

2545

--

contra-senha

avaliacao

1234

1234

++++

1234

1243

++--

1234

1423

+---

1234

4321

----
@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
@dudumendes
@dudumendes

Obtendo resultado

Como já foram realizadas algumas refatorações
o código já passa a nos ajudar
@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
@dudumendes
@dudumendes

Próximo cenário?
sem acertos

senha
!
1234
!

com 03 dígitos corretos

contrasenha
5555

avaliacao

com 01 dígito correto
senha
!
1234
!
1234

avaliacao

contra-senha

1555

+

2555

-

senha
!1234

contra-senha

avaliacao

5234

+++

1234
!
1234

5134

++-

5124

+--

!1234

5123

---

com todos corretos
senha

com 2 dígitos corretos
senha
!
1234

contra-senha

avaliacao

5254

++

1234

5154

+-

1234

2545

--

contra-senha

avaliacao

1234

1234

++++

1234

1243

++--

1234

1423

+---

1234

4321

----
@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
@dudumendes
@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
@dudumendes
@dudumendes

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

Em seguida?
@dudumendes

Em seguida
Remover bad smells
Variáveis temporárias
Métodos longos estruturados
Classes com responsabilidades demais
Extrair classe
@dudumendes

O que vimos?
@dudumendes

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

O que vimos?
Iniciar os testes baseados em cenários previamente
Nunca codifique uma funcionalidade nova sem um teste falhando
@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
@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
@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
@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
@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
@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
@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
@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.

TDD - Prática com RSpec