usar um trecho de código que já vimos antes para exemplificar isso.
Imagine que você está construindo um jogo e você quer ele se comunique com
o jogador via Twitter. Você poderia ter duas classes para esse sistema, a classe Game e uma classe chamada TwitterUi, que seria responsável pela interface de escrita
e leitura do Twitter. Vamos começar a escrever um teste para a classe Game usando
subject para explicitar como construir um objeto game e o let para mostrar
quem são os colaboradores do system under test (SUT):
describe Game do
subject(:game) { Game.new(ui) }
let(:ui) { TwitterUi.new('sandbox_username',
'sandbox_password') }
end
Agora digamos que queiramos escrever um teste que especifique que quando o
jogador acertar o alvo, o jogo deve parabenizar o jogador. Poderíamos continuar o
código acima e escrever esse teste assim:
describe Game do
subject(:game) { Game.new(ui) }
let(:ui) { TwitterUi.new('sandbox_username', 'sandbox_password') }
it "congratulates the player when the player hits the target" do
game.player_hits_target
expect(game.output).to include("Congratuations!")
78
Casa do Código
Capítulo 4. Organização, refatoração e reuso de testes com o RSpec
end
end
Perceba que para acessar o subject basta chamarmos o método que foi defi-
nido por ele. No caso acima, foi o método game.
Explicitar no teste como se cria uma instância do seu objeto e quem são os co-
laboradores é uma ótima forma de organizar seu teste. Isso porque você já mostra
para o leitor na introdução do seu teste um exemplo de algo que é essencial para usar o seu objeto, que é como construir uma instância dele.
4.6
Reuso de testes
Agora que já vimos sobre os RSpec hooks, sobre como refatorar nossos testes usando
os eles e também sobre como organizar nossos testes, vamos ver um pouco sobre
como reutilizar nossos testes.
O RSpec oferece uma funcionalidade bem interessante para reutilizar testes em
diferentes contextos, o nome dessa funcionalidade é shared examples. Mas onde que
seria necessário reutilizar testes? Vamos ver um exemplo.
Imagine que você está desenvolvendo um sistema de publicação de conteúdo.
Até então, o seu sistema só gerencia blog posts. Um requisito do seu sistema é que
se um blog post for publicado, é necessário que você salve a data de publicação dele.
Sabendo disso, você começa e escrever a seguinte spec para a sua classe BlogPost:
describe BlogPost do
describe "#publish" do
it "saves the publication date" do
blog_post = BlogPost.new
blog_post.publish!
today = Time.now.strftime("%Y-%m-%d")
expect(blog_post.published_on).to eq(today)
end
end
end
Para fazer esse teste passar, você escreve a classe BlogPost do seguinte modo:
class BlogPost
attr_reader :published_on
79
4.6. Reuso de testes
Casa do Código
def publish!
today = Time.now.strftime("%Y-%m-%d")
@published_on = today
end
end
Depois de um tempo, seu sistema foi sendo cada vez mais usado e você decide
que agora ele cuidará também de publicação de papers acadêmicos. Um dos requisi-
tos de publicação de papers é o mesmo da publicação de blog posts, você deve salvar
a data que o paper foi publicado. Como um bom praticante de TDD, você escreve o
seguinte teste para a classe Paper:
describe Paper do
describe "#publish" do
it "saves the publication date" do
paper = Paper.new
paper.publish!
today = Time.now.strftime("%Y-%m-%d")
expect(paper.published_on).to eq(today)
end
end
end
Para fazer esse teste passar, você escreve o seguinte código:
class Paper
attr_reader :published_on
def publish!
today = Time.now.strftime("%Y-%m-%d")
@published_on = today
end
end
Você para um pouco, olha as duas classes, os dois testes e percebe que tem total
duplicação entre os dois:
class BlogPost
attr_reader :published_on
80
Casa do Código
Capítulo 4. Organização, refatoração e reuso de testes com o RSpec
def publish!
today = Time.now.strftime("%Y-%m-%d")
@published_on = today
end
end
class Paper
attr_reader :published_on
def publish!
today = Time.now.strftime("%Y-%m-%d")
@published_on = today
end
end
Para eliminar essa duplicação, você pensa em extrair um módulo que conte-
nha as regras de negócio de um objeto publicável. Esse módulo poderia se chamar
Publishable. A idéia é basicamente extrair o comportamento duplicado de lógica
de publicação nas classes BlogPost e Paper para esse módulo.
Nós poderíamos escrever um teste para esse módulo do seguinte modo:
class PublishableObject
include Publishable
end
describe "A published object"
do
subject { PublishableObject.new }
describe "#publish" do
it "saves the publication date" do
subject.publish!
today = Time.now.strftime("%Y-%m-%d")
expect(subject.published_on).to eq(today)
end
end
end
Agora vamos parar um pouco para entender o teste acima. Primeiro nós defi-
nimos uma classe só para esse teste, a PublishableObject, que inclui o módulo
81
4.6. Reuso de testes
Casa do Código
que queremos testar. Depois disso, nós chamamos o método subject sem pas-