Notação
Class#instance_method
e
Class.class_method
Em Ruby, existe uma notação muito usada para se referen-
ciar a um método de instância ou de classe, que é a notação
Class#instance_method e Class.class_method.
Para métodos de instância você se referencia utilizando o caractere
# entre o nome da classe e o nome do método:
Class#instance_method
No caso da nossa pilha, temos um método de instância cha-
mado push, portanto podemos nos referenciar a ele com a notação
Stack#push.
Para métodos de classe você se referencia utilizando o caractere .
entre o nome da classe e o nome do método:
Class.class_method
No caso da nossa pilha, ela tem um método de classe cha-
mado initialize, podemos nos referenciar a ele com a notação
Stack.initialize.
Usando subject e let para organizar SUT e objetos colaboradores
Agora vamos olhar como você pode usar os métodos subject e let do RSpec
para organizar seus testes. Mas antes disso, como ainda não ainda vimos nenhum
desses dois métodos, vamos primeiro olhar cada um isoladamente.
O RSpec oferece um método chamado subject para definir o SUT ( system
under test, o objeto sendo testado). Para entendermos como ele pode ser usado,
segue um exemplo de código com o seu uso:
describe Array, "with some elements" do
75
4.5. Organizando seus testes
Casa do Código
subject(:array) { [1,2,3] }
it "should have the prescribed elements" do
array.should == [1,2,3]
end
end
No teste acima nós usamos o subject para definir um método chamado
array,
que quando executado, retorna o array [1, 2, 3], que é SUT do nosso
teste.
Perceba que você poderia re-escrever o código acima usando um before hook:
describe Array, "with some elements" do
before do
@array = [1,2,3]
end
it "should have the prescribed elements" do
@array.should == [1,2,3]
end
end
No entanto, o uso do método subject no caso acima é mais indicado, já que
ele deixa explícito que o objeto sendo manipulado é o SUT.
A diferença entre usar o subject e um before hook para o setup do SUT, é que
o subject foi feito para manipular o SUT, já o before hook serve para fazer o setup
do teste do teste como um todo, ou seja, o before hook é mais genérico.
Agora que já vimos uma apresentação do subject, vamos falar do let.
O let serve para definir um helper method (método auxiliar) para o seu teste.
Vamos começar a entender o let analisando o seguinte exemplo:
describe Game do
let(:ui) { TwitterUi.new("sandbox_username", "sandbox_password") }
end
O código acima cria um método chamado ui que quando chamado irá retornar
um objeto da classe TwitterUi. Esse método pode ser usado dentro de um teste,
como a seguir:
describe Game do
before do
76
Casa do Código
Capítulo 4. Organização, refatoração e reuso de testes com o RSpec
@game = Game.new
end
let(:ui) { TwitterUi.new('sandbox_username', 'sandbox') }
it "congratulates the player when the player hits the target" do
@game.ui = ui # chamando o método definido pelo let
@game.player_hits_target
expect(@game.output).to include("Congratulations!")
end
end
Uma outra característica interessante do let é que sua execução é lazy. Ou seja,
o bloco de código passado para ele só vai ser executado se você chamar o método
definido pelo let. Esse comportamento é diferente do comportamento do before
hook, que sempre executa seu bloco de código para todos os examples do seu escopo.
Para esclarecer esse comportamento, segue um exemplo:
describe "The lazy-evaluated behavior of let" do
before { @foo = 'bar' }
let(:broken_operation) { raise "I'm broken" }
it "will call the method defined by let" do
expect {
expect(@foo).to eq('bar')
broken_operation
}.to raise_error("I'm broken")
end
it "won't call the method defined by let" do
expect {
expect(@foo).to eq('bar')
}.not_to raise_error
end
end
Agora que já conhecemos o subject e o let, vamos aprender um modo de
como usá-los para organizar nossos testes.
77
4.5. Organizando seus testes
Casa do Código
Como você deve saber, em programação orientada a objetos, para que um ob-
jeto possa realizar sua responsabilidade, ele as vezes depende de outros objetos. Esses objetos dos quais ele depende são chamados seus colaboradores. Já que um objeto
depende de outros para realizar sua responsabilidade, uma prática muito comum é
passar para o construtor de uma classe os objetos das quais ela depende como pa-
râmetros. Essa prática se chama injeção de dependência, nós veremos um exemplo
concreto dela no capítulo 5.
Pois bem, se um objeto depende de outros para ser construído e a etapa de cons-
trução de um objeto é a etapa mais básica no seu ciclo de vida, então pode valer a
pena explicitar no seu teste como é feita a construção desse objeto e quem são os seus colaboradores. Afinal, se alguém quiser entender como usar o seu código, a primeira
coisa que essa pessoa deve entender é como criar uma instância válida do seu objeto.
Em um teste com RSpec, para deixarmos explícito como criar um dado objeto e
quais são seus colaboradores, podemos usar os métodos subject e let. Vamos