Há algum tempo atrás, escrevi umas groselhas sobre Jasmine: um post foi mais uma introdução sobre o framework e o outro post foi sobre os matchers que o Jasmine nos oferece.
O que são os spies
?
Basicamente quando usamos Jasmine especificamos nos testes como nosso código deve (ou deveria) funcionar. Ao usar um spy
conseguimos fazer com que ele fique de olho em partes do nosso programa, assim essa parte pode ser substituída por um spy
(que pode ser uma função ou objeto). Assim, conseguimos testar se determinada função está sendo chamada e se está sendo chamada com os argumentos esperados. Confuso? Vamos lá…
Imagine que temos uma brincadeira assim:
Acima, temos um construtor de sanduíche ¯\_(ツ)_/¯ e dois métodos: um que vai adicionar ingredientes ao nosso sanduíche e outro que irá retornar a lista com os ingredientes do sanduíche super gostoso.
Agora, como testamos pra saber se os métodos estão funcionando do jeito que esperamos? Podemos começar com algo assim:
O que fizemos no código acima foi o seguinte:
- criamos uma variável
fabeni
; - através do nosso
beforeEach
, antes de cadaspec
é criado um novoSandwich
e atrelado àfabeni
; - criamos um
spy
no métodoaddIngredient
, para ser utilizado nas specs (através dospyOn
, passamos como primeiro parâmetro o objeto relacionado e como segundo parâmetro o método que vamos espionar); - adicionamos 2 ingredientes no sanduíche através do método
addIngredient
; - criamos uma primeira
spec
que espera que o métodoaddIngredient
tenha sido chamado (através do matchertoHaveBeenCalled()
).
Assim, se rodarmos nosso teste, vamos ver que ele passou, ou seja, o método addIngredient
está sendo chamado perfeitamente.
Agora, se quisermos verificar se esse mesmo método está sendo chamado com os argumentos corretos poderíamos adicionar a seguinte spec:
Nessa nova spec utilizamos do matcher toHaveBeenCalledWith()
com o argumento que esperamos que tenha sido chamado (conforme a chamada que fizemos no beforeEach
). Feito isso, ao rodarmos nossos testes:
Resumidamente o spyOn
substitui a função, interceptando assim as suas chamadas e acompanhando algumas informações importantes sobre ela para utilizarmos em nossas specs. Aí temos um ponto a se considerar: dessa maneira perdemos as capacidades da função original. Para resolver isso podemos usar o andCallThrough()
. Vamos lá:
Acima, apenas preparamos o terreno:
- criamos duas variáveis
fabeni
efabeniBurger
; - novamente utilizamos o
beforeEach
para fazermos algumas coisas antes de cada spec; - criamos um
spy
no métodoaddIngredient
, para ser utilizado nas specs e encadeamos o.and.callThrough()
para transmitirmos as chamadas a ele através da função original; - adicionamos 2 ingredientes no sanduíche através do método
addIngredient
; - referenciamos em
fabeniBurger
o valor de retorno do métodomySandwich()
defabeni
.
Com isso então, podemos criar nossas specs:
No exemplo acima, criamos duas specs:
- a primeira simplesmente verifica se o método
mySandWich
foi chamado; - e a segunda verifica se o valor retornado desse mesmo método (no caso referenciado na variável
fabeniBurger
) é igual ao que esperamos (de acordo com o que foi setado nobeforeEach
).
Aí é só rodarmos nossos testes:
Valeu ao grande Weslley Araujo pela ajuda na revisão do post.