4. @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
10. @dudumendes
O que veremos?
Iniciar os testes baseados em cenários previamente definidos
Nunca codifique uma funcionalidade nova sem um teste falhando
11. @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
12. @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
13. @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
14. @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
15. @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
16. @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
17. @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
19. @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
20. 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
21. @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: + > -
22. @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
25. @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:”
36. @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
37. @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ê
38. @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
39. @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
46. @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
48. @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
50. @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
54. @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
56. @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
58. @dudumendes
O ciclo básico do TDD
Escrever um
teste unitário
que falha
Fazer um código
passar no teste
Refatorar
59. @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
64. @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
66. @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
67. @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 }
68. @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
69. @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 -
70. @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>”
73. @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
!
75. @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
88. @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
90. @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
93. @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
96. @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
98. 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
100. @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
101. 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
102. 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
104. @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
108. @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
109. @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
110. @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
117. @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
118. @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
123. @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
124. @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
125. @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
126. @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á
127. @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
128. @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
137. @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
143. @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
145. @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
153. @dudumendes
O que vimos?
Iniciar os testes baseados em cenários previamente
Nunca codifique uma funcionalidade nova sem um teste falhando
154. @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
155. @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
156. @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
157. @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
158. @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
159. @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
160. @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