5. @dudumendes
Criando doubles
método double
algum_double = double(“um_double”)
algum_stub = stub(“um_stub”)
algum_mock = mock(“um_mock”)
Argumento string é opcional, mas recomendado
pode ser utilizado um símbolo
Utilizado na mensagens de falha
Geram instâncias de RSpec::Mocks::Mock
6. @dudumendes
Métodos Stubs
Método em que se pode programar uma resposta pré-
definida de um objeto,
que será retornada durante a execução de exemplo
utiliza-se quando não se tem expectativas sobre a
execução
8. @dudumendes
Classe inexistente
Identificador do mock
describe "classe Candidato" do
métodos e retornos
it "retorna nome e partido" do
candidato = mock(:candidato)
candidato.stub(:nome => "Luiz Augusto",
:partido => "PRAONDEEH")
expect(candidato.nome).to eql("Luiz Augusto")
expect(candidato.partido).to eql("PRAONDEEH")
end
end
9. @dudumendes
Classe inexistente / atalho
describe "classe Candidato" do Identificador do mock
it "retorna nome e partido" do métodos e retornos
candidato = mock(:candidato,
:nome => "Luiz Augusto",
:partido => "PRAONDEEH")
expect(candidato.nome).to eql("Luiz Augusto")
expect(candidato.partido).to eql("PRAONDEEH")
end
end
12. @dudumendes
o método subject
Subject
O subject de um exemplo é o objeto que está sendo
descrito, exercitado
Se o subject é uma classe chamada Usuario
uma instância de Usuario é fornecida
automaticamente pelo método subject
subjects são instanciados nos blocos before
13. @dudumendes
describe Professor do
it "eh uma instancia de Professor" do
expect(subject).to be_a(Professor)
end
it "nao deve ser um aluno" do
expect(subject).not_to be_an(Aluno)
end
it "nao possui nome definido" do
expect(subject.nome).to be_nil
end
end Professor
eh uma instancia de Professor
nao deve ser um aluno
nao possui nome definido
14. describe Candidato do @dudumendes
it "possui email" do
subject.stub(:email => "luiz@email.com")
expect(subject.email).to eql("luiz@email.com")
end
it "pode ter partido nulo" do
subject.stub(:partido)
expect(subject.partido).to be_nil
end
it "possui email alternativo" do
subject.stub(:emailAlternativo) do
"luiz@alternativo.com"
end
expect(subject.emailAlternativo).to eql("luiz@alternativo.com")
end
it "possui email e partido" do
subject.stub(:email => "luiz@email.com", :partido => "PUTZ")
expect(subject.email).to eql("luiz@email.com")
expect(subject.partido).to eql("PUTZ")
end
end
16. @dudumendes
Funcionario
Crie specs com mocks para a classe funcionario e
exercite expectativas em valores pré-configurados
Faça os testes falharem e passarem para comparar
os resultados
Crie 02 versões
um spec com uma classe que não existe
e outro com utilizando o subject
19. describe UrnaEletronica do
it "retorna um voto" do
subject.stub(:apurar).and_return("Candidato 1")
expect(subject.apurar).to eql("Candidato 1")
end
end
20. describe UrnaEletronica do
it "retorna votos em sequencia" do
subject.stub(:apurar).and_return("C1", "C2", "C3")
expect(subject.apurar).to eql("C1")
expect(subject.apurar).to eql("C2")
expect(subject.apurar).to eql("C3")
end
end
23. describe "classe Estacao" do
it "retorna a previsao de temperatura maxima" do
subject.stub_chain(:termometro, :maxima => 32)
expect(subject.termometro.maxima).to eql(32)
end
it "retorna a previsao de temperatura minima" do
subject.stub_chain(:termometro, :minima => 32)
expect(subject.termometro.minima).to eql(32)
end
end
26. describe Eleitor do
it "deve votar" do
Eleitor.any_instance.stub(:votar => true)
eleitor = Eleitor.new
expect(eleitor.votar).to be_true
novo_eleitor = Eleitor.new
expect(novo_eleitor.votar).to be_true
end
end
28. @dudumendes
passando argumentos
método with
O with
passa os parâmetros que devem ser passados a um
método de stub
valor
hash
anything, any_args, hash_including(),
hash_not_including(), instance_of
29. describe Eleitor do
it "deve votar" do
Eleitor.any_instance.stub(:votar).with(:voto).and_return(true)
eleitor = Eleitor.new
expect(eleitor.votar(:voto)).to be_true
novo_eleitor = Eleitor.new
expect(novo_eleitor.votar(:voto)).to be_true
end
end
30. describe Candidato do
it "inicializa com um numero" do
Candidato.stub(:new).with(:numero => 99)
Candidato.new :numero => 99
end
end
31. it "inicializa com qualquer valor" do
Candidato.stub(:new).with(any_args)
Candidato.new
Candidato.new(:nome => "Valor", :idade => 19)
end
32. it "inicializa com nome especifico" do
Candidato.stub(:new).with(
hash_including(:nome => "Joao Luiz"))
Candidato.new(:nome => "Joao Luiz", :idade => 19)
end
33. it "inicializa com nome especifico" do
Candidato.stub(:new).with(
hash_not_including(:nome => "Joao Luiz"))
Candidato.new(:idade => 19)
end
34. it "escreve um nome" do
subject.stub(:nome=).with(/Joao/)
subject.nome= "Joao Luiz"
end
35. it "o nome deve ser uma String" do
subject.stub(:nome=).with(instance_of(String))
subject.nome= 3
end
36. it "deve ser ficha limpa" do
subject.stub(:ficha_limpa=).with(boolean)
subject.ficha_limpa=true
end
37. describe Candidato do
it "inicializa com qualquer valor" do
Candidato.stub(:new).with(anything)
Candidato.new(:nome => "Valor", :idade => 19)
end
end
39. describe "Bar" do @dudumendes
it "so pode vender para maior de 18" do
cliente = double(:cliente)
cliente.stub(:beber) do |idade|
if idade >= 18
"OK"
else
"ERROR"
end
end
expect(cliente.beber(20)).to eql "OK"
expect(cliente.beber(10)).to eql "ERROR"
end
end
41. describe Eleitor do
it "raises" do
subject.stub(:idade).and_raise("Nao implementado")
expect { subject.idade }.to raise_error("Nao implementado")
end
it "throws" do
subject.stub(:votar).and_throw(:nao_comparecimento)
expect { subject.votar }.to throw_symbol(:nao_comparecimento)
end
end
43. @dudumendes
describe Inscricao do
it "utiliza o nome do candidato no cabecalho" do
candidato = double("candidato")
candidato.stub(:nome).and_return("Luiz")
inscricao = Inscricao.new(candidato)
expect(inscricao.gerar).to eql "Inscricao de Luiz"
end
end
44. @dudumendes
describe Inscricao do
it "utiliza o nome do candidato no cabecalho" do
candidato = double("candidato")
candidato.stub(:nome).and_return("Luiz")
inscricao = Inscricao.new(candidato)
expect(inscricao.gerar).to eql "Inscricao de Luiz"
end
end
Inscricao: sujeito
Candidato: não é o foco do exemplo, coloborador
imediato
Teste double para atuar como um candidato
47. @dudumendes
describe Inscricao do
it "utiliza o nome do candidato no cabecalho" do
candidato = double("candidato")
candidato.stub(:nome).and_return("Luiz")
inscricao = Inscricao.new(candidato)
expect(inscricao.gerar).to eql "Inscricao de Luiz"
end
end
48. @dudumendes
Estratégias
Triangulação
Criar um outro exemplo utilizando um valor diferente que
força a generalização do método
Verificacar duplicação
Verifica-se que "Inscricao de Luiz" é uma duplicação
aparece no spec e no método
consequência: remoção
49. @dudumendes
Estratégias
Triangulação
Exige 02 exemplos para que o sujeito tenha o
comportamento esperado
Verificacar duplicação
Pode legar valores “hard-coded” à implementação
52. @dudumendes
describe Inscricao do
it "utiliza o nome do candidato no cabecalho" do
candidato = double("candidato")
candidato.should_receive(:nome).and_return("Luiz")
inscricao = Inscricao.new(candidato)
expect(inscricao.gerar).to eql "Inscricao de Luiz"
end
end
53. @dudumendes
class Inscricao
def initialize(candidato)
@candidato = candidato
end
def gerar
"Inscricao de Luiz"
end
end
Failure/Error: candidato.should_receive(:nome).and_return("Luiz")
(Double "candidato").nome(any args)
expected: 1 time
received: 0 times
# ./inscricao_spec_2.rb:14:in `block (2 levels) in <top (required)>'
Finished in 0.00216 seconds
1 example, 1 failure
55. @dudumendes
Stubs + Message Expectations
O sentido de existir métodos que retornam o mesmo
objeto
dar mais semântica ao teste
identificar sujeito e colaboradores
intenção incorporada no código
56. @dudumendes
it "cria um log quando o gerar eh chamado" do
candidato = stub("candidato")
candidato.stub(:nome).and_return("Luiz")
logger = mock("logger")
inscricao = Inscricao.new(candidato, logger)
logger.should_receive(:log).with("Inscricao de Luiz")
inscricao.gerar
end
61. @dudumendes
Counts
should_receive
A expectativa default gerada por uma chamada a
should_receive é que a mensagem seja chamada
apenas 01 única vez
é possível configurar o número de vezes através de
métodos como exactly(), at_least(), at_most(),
once, twice, combinados com o método times
62. @dudumendes
describe "classe Aluno" do
it "chama new" do
aluno = double(:aluno)
aluno.should_receive(:nome).and_return("Jessica")
expect(aluno.nome).to eql "Jessica"
end
end
63. @dudumendes
describe "classe Aluno" do
it "chama new" do
aluno = double(:aluno)
aluno.should_receive(:nome).and_return("Jessica")
expect(aluno.nome).to eql "Jessica"
expect(aluno.nome).to eql "Jessica"
end
end
64. @dudumendes
exactly().times
describe "classe Aluno" do
it "chama new" do
aluno = double(:aluno)
aluno.should_receive(:nome)
.and_return("Jessica").exactly(1).times
expect(aluno.nome).to eql "Jessica"
end
end
65. @dudumendes
at_most().times
describe "Rede" do
it "deve ser solicitadas no maximo 5 conexoes" do
rede = double(:rede)
rede.should_receive(:open_connection).at_most(4).times
rede.open_connection
rede.open_connection
rede.open_connection
rede.open_connection
end
end
66. @dudumendes
at_least().times
describe "Rede" do
it "deve ser solicitadas no maximo 5 conexoes" do
rede = double(:rede)
rede.should_receive(:open_connection).at_least(2).times
rede.open_connection
rede.open_connection
rede.open_connection
rede.open_connection
end
end
67. @dudumendes
once, twice
describe "Conta" do
it "deve gerar extrato 01 vez" do
conta = double(:conta)
conta.should_receive(:gerar_extrato).once
conta.gerar_extrato
end
it "deve checar valor 02 vezes" do
conta = double(:conta)
conta.should_receive(:checar_valor).twice
conta.checar_valor
conta.checar_valor
end
68. @dudumendes
it "nao deve abrir conexao apos ping falso" do
@rede.stub(:ping).and_return(false)
@rede.should_receive(:open_connection).exactly(0).times
@rede.open_connection if @rede.ping
end
71. @dudumendes
it "nao deve abrir conexao apos ping falso" do
@rede.stub(:ping).and_return(false)
@rede.should_not_receive(:open_connection)
@rede.open_connection if @rede.ping
end
it "nao deve abrir conexao apos ping falso" do
@rede.stub(:ping).and_return(false)
@rede.should_receive(:open_connection).never
@rede.open_connection if @rede.ping
end
73. it "deve fazer campanha antes de votar" do
subject.stub(:fazer_campanha).ordered
subject.stub(:votar).ordered
subject.fazer_campanha
subject.votar
end
75. @dudumendes
Transferencia
Contexto
Testar a transferencia de valores entre 02 contas
A transferência é realizada por um objeto chamado
Transferencia
O objeto guarda as 02 contas e executa uma
transferência de valores entre elas
O sujeito a se testar é o objeto Transferencia
As contas ainda não estão implementadas
76. @dudumendes
Transferencia
Exemplos
o objeto Transferencia deve ser criado com 01 conta de origem, 01 conta de
destino e um valor
ao se executar a transferência, a conta de origem deve receber a mensagem
transferir
o 1.º argumento deve ser a conta de destino
o 2.º argumento deve uma instância de Fixnum
o 2.º argumento deve ter o valor
deve ser lançado um erro com a mensagem “Saldo insuficiente”, caso o saldo
da conta de origem seja menor que o valor solicitado
o saldo deve ser conferido antes de transferir
79. @dudumendes
Isolar dependências
Dependências problemáticas
configuração e construção cara
funcionamento lento
dependência de sistemas externos
rede, servidores, sistema de arquivos
Mock para isolar os exemplos das dependências e
incrementar potenciais pontos de falha
80. @dudumendes
BD
Interface para BD
Sujeito
Interface de rede Web
81. @dudumendes
Stub
Interface para BD
Exemplo Sujeito
Stub
Interface de rede
82. @dudumendes
Isolação de comportamentos
não determinísticos
Dependência de sistemas externos
pode ser fonte de não determinismo
arquivos corrompidos, falhas de disco, time out
de rede
MOCK e obtenha um ambiente controlado
84. @dudumendes
Stub do
Exemplo Sujeito Dado
3,5,6,6,6,7,10
85. @dudumendes
Progresso sem
implementações
Às vezes, dependemos de comportamentos de
objetos que outros times não implementaram ainda
As interfaces podem já ter sido projetadas
Oportunidade para explorar dependências e
possibilidades de interfaces alternativas
86. @dudumendes
Descobrimento de interface
Ao exercitar a implementação de um objeto
pode-se descobrir que ele necessita de
comportamento de um outro que ainda não existe
método não pensado na fase de projeto
até mesmo objeto
89. @dudumendes
it "cria um log quando o gerar eh chamado" do
candidato = stub("candidato")
candidato.stub(:nome).and_return("Luiz")
logger = mock("logger")
inscricao = Inscricao.new(candidato, logger)
logger.should_receive(:log).with("Inscricao de Luiz")
inscricao.gerar
end
90. @dudumendes
Focar na interação
ao invés do estado
Sistemas orientados a objetos dizem respeito à
interfaces e interações
O estado não faz parte do comportamento
observável
Exemplos serão menos frágeis
se evitar o foco no estado
91. @dudumendes
describe Inscricao do
it "utiliza o nome do candidato no cabecalho" do
candidato = stub("candidato", :nome => "Luiz")
inscricao = Inscricao.new(candidato)
expect(inscricao.gerar).to eql "Inscricao de Luiz"
end
end
92. @dudumendes
describe Inscricao do
it "utiliza o nome do candidato no cabecalho" do
candidato = double("candidato")
candidato.should_receive(:nome).and_return("Luiz")
inscricao = Inscricao.new(candidato)
expect(inscricao.gerar).to eql "Inscricao de Luiz"
end
end