expect(cart.empty?).to be_true
end
end
end
Acontece que toda vez que um objeto tem um predicate method (método que
termina com ?), o RSpec gera um matcher específico para esse método dinamica-
mente. No caso do exemplo acima, ao invés de fazer:
37
3.6. Matchers relacionados a arrays
Casa do Código
expect(cart.empty?).to be_true
Você pode utilizar um predicate matcher para re-escrever o teste do seguinte
modo:
expect(cart).to be_empty # chama o método cart.empty?
O que o RSpec faz é gerar para todo predicate method chamado method_name?
um matcher chamado be_method_name. Foi o que fizemos acima quando usamos
o matcher
be_empty referente ao predicate method empty?. Esse tipo de matcher
é bem usado porque os predicate methods são uma convenção bastante usada na
comunidade Ruby.
Os predicate matchers ainda tem outras três formas.
A segunda forma é
quando o RSpec gera um matcher have_method_name para métodos da forma
has_method_name?.
Um exemplo desse caso pode ser visto para o método
has_key? de um hash:
hash = { key: 1 }
expect(hash).to have_key(:key) # chama o método hash.has_key?(:key)
Você pode utilizar essa forma de predicate matcher para os seus próprios ob-
jetos também. Imagine o exemplo da classe Cart, ela poderia ter o método
has_products? e você poderia espefificar esse método do seguinte modo:
describe Cart do
describe "#has_products?" do
it "returns true if it has products" do
product = Product.new
cart = Cart.new(product)
expect(cart).to have_products # chama o método cart.has_products?
end
end
end
A terceira e quarta formas dos predicate matchers são os matchers
be_a_method_name e
be_an_method_name.
Para entender essas últimas
formas, imagine que sua classe Cart tem os métodos thing? e object?, e
ambos devem retornar true. Você pode especificar esses métodos do seguinte
modo:
38
Casa do Código
Capítulo 3. Introdução ao básico do RSpec
expect(cart).to be_a_thing
# chama o método cart.thing?
expect(cart).to be_an_object # chama o método cart.object?
Matchers para exceptions
O RSpec oferece um matcher para você especificar que um método levanta uma
determinada exception, é o RaiseError Matcher. Você pode usá-lo com o método
raise_error e seu alias raise_exception:
expect { raise }.to raise_error
expect { raise }.to raise_exception
Perceba que diferentemente do modo padrão de escrever uma expectation, o
argumento que é passado para o método expect é um bloco:
# correto
expect { raise }.to raise_error
# correto
expect do
raise
end.to raise_error
# errado
expect(raise).to raise_error
É possível verificar também se a exception levantada é de uma classe específica:
expect { raise RuntimeError }.to raise_error(RuntimeError)
expect { raise StandarError }.to_not raise_error(RuntimeError)
Por fim, você pode verificar também a mensagem da exception levantada:
expect { raise 'error message' }.to raise_error('error message')
expect { raise 'wrong message' }.to_not raise_error('error message')
Matchers para comparação de números
Para comparar se um valor é igual a um certo número você deve usar o eq matcher
: expect(hugo_age).to eq(27). Mas, e para comparar se um número é menor
ou maior que outro? Para esses casos você tem os seguintes matchers:
39
3.6. Matchers relacionados a arrays
Casa do Código
expect(7).to be < 10
expect(7).to be > 1
expect(7).to be <= 7
expect(7).to be >= 7
Matchers relacionados a números float
Fazer a verificação de números float pode ser problemático, pois devido a parte
fracionária do número, não dá para simplesmente utilizar um matcher de equidade.
Imagine por exemplo que você voltou para as aulas de geometria plana e quer con-
firmar que você sabe que o valor de Pi é 3.14:
expect(Math::PI).to eq(3.14) # executa Math::PI == 3.14
Acontece que o teste acima vai falhar, porque Pi não é exatamente igual a 3.14, ele
é aproximadamente 3.14. Uma aproximação de Pi com mais casas decimais poderia
ser por exemplo 3.141592653589793.
Com o problema acima em mente, o RSpec nos oferece o BeWithin matcher, que
serve para fazer comparações entre números de forma aproximada. Poderíamos re-
escrever o teste acima do seguinte modo com esse matcher:
expect(Math::PI).to be_within(0.01).of(3.14)
O que o teste acima está fazendo é comparar se o valor de Math::PI é maior
ou igual a 3.14 - 0.01 ou menor ou igual ao valor de 3.14 + 0.01. Ou seja,
para uma expectation genérica no seguinte formato:
expect(actual).to be_within(delta).of(expected)
O que esse matcher faz é verificar se a seguinte expressão é verdadeira:
(expected - delta)
<= actual <= (expected + delta)
Matchers para ranges
Para versões do Ruby a partir da 1.9, o RSpec oferece um matcher para verificar
se um ou mais elementos pertecem a um dado range, é o Cover Matcher. Você pode
usá-lo da seguinte forma:
range = (1..10)
40
Casa do Código
Capítulo 3. Introdução ao básico do RSpec
expect(range).to cover(1)
expect(range).to cover(10)
expect(range).to cover(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)