Veja aqui os artigos anteriores que escrevi sobre Jasmine.
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:
function Sandwich() { this.ingredients = []; } Sandwich.prototype.addIngredient = function (ingredient) { this.ingredients.push(ingredient); }; Sandwich.prototype.mySandwich = function() { return this.ingredients; };
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:
describe('A Sandwich spy', function() { var fabeni; beforeEach(function() { fabeni = new Sandwich(); spyOn(fabeni, 'addIngredient'); fabeni.addIngredient('bread'); fabeni.addIngredient('cheese'); }); it('tracks the spy for addIngredient method', function() { expect(fabeni.addIngredient).toHaveBeenCalled(); }); });
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, podemos adicionar a seguinte spec:
... it('tracks the spy for addIngredient method with the correct arguments', function() { expect(fabeni.addIngredient).toHaveBeenCalledWith('bread'); expect(fabeni.addIngredient).toHaveBeenCalledWith('cheese'); }); ...
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á:
describe('A Sandwich spy with call through', function() { var fabeni, fabeniBurger; beforeEach(function() { fabeni = new Sandwich(); spyOn(fabeni, 'mySandwich').and.callThrough(); fabeni.addIngredient('bread'); fabeni.addIngredient('cheese'); fabeniBurger = fabeni.mySandwich(); }); });
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:
... it('tracks the spy for mySandwich method', function() { expect(fabeni.mySandwich).toHaveBeenCalled(); }); it('returns my sandwich', function() { expect(fabeniBurger).toEqual(['bread', 'cheese']); }); ...
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 artigo.
Gostou? Escrevi alguma groselha? Quer melhorar? Abra uma issue com a hashtag 1postperweek e vamos conversar.
***
Artigo publicado originalmente em: http://www.raphaelfabeni.com.br/jasmine-criando-spies/