# SpyOn

![](/files/-MdMcJKylldYFFGNVQs_)

{% hint style="info" %}
Fonte: [documentação](https://jestjs.io/docs/jest-object#jestspyonobject-methodname)&#x20;
{% endhint %}

{% hint style="info" %}
Códigos [aqui](https://github.com/JorgeGuerraPires/curso-mongoose/tree/mock_spy_1), contudo, tenta primeiro!&#x20;
{% endhint %}

Essa função é usada para se criar "espiões": uma função que garante que um determinado método é chamado.

{% hint style="info" %}
**Nota 28/10/21**. existe uma frase no mundo dos testes que diz "testa comportamento, não implementação". O motivo é que ao se testar implementaçao, se injessa o código, tornando refazer (*refactoring*) depois difícil ou mesmo impossível. Isso quer dizer que spies devem ser usado com cautela, uma vez que "olham" dentro do código, criando testes que pode ser específicos a uma implementação.&#x20;
{% endhint %}

Da documentação oficial do Jest:

```javascript
//video.js
const video = {
  play() {
    return true;
  },
};

module.exports = video;
```

Agora, precisamos do teste:

```javascript
//video.test.js
const video = require('./video');

test('plays video', () => {
  const spy = jest.spyOn(video, 'play');
  const isPlaying = video.play();

  expect(spy).toHaveBeenCalled();// gera o mesmo resultado
  expect(isPlaying).toBe(true); // gera o mesmo resultado

  spy.mockRestore();//reinicia tudo, 
  // spy guarda informações como chamada ao método espionado
});
```

## Espiando e mocando&#x20;

Geralmente, espião somente olha🧐🧐, contudo, Jest possibilita também de se tomar "providências", vamos precisar disso no nosso teste.&#x20;

```javascript
test('plays video, second test. Estamos testando se conseguimos mocar depois de espiar', () => {
    //Vamos reenscrever o que será retornado
    const spy = jest.spyOn(video, 'play')
                    .mockImplementation(scalar => 42 + scalar);
    
    const isPlaying = video.play(10);

    expect(spy).toHaveBeenCalled();// gera o mesmo resultado
    expect(isPlaying).toBe(52); // gera o mesmo resultado

    spy.mockRestore();//reinicia tudo, 
    // spy guarda informações como chamada ao método espionado
});

```

Na linha 4, além de espiar na linha 3, dizemos o que deve ser feito: estamos reinscrevendo o método sendo espionado. Por que?? Como será visto, essa abordagem de cadeia é necessária para garantir a execução do Mongoose.&#x20;

{% hint style="info" %}
Note que estamos com dois *expects* no mesmo teste, geralmente isso não é uma boa prática. Faça você mesmo o teste, faça o teste falhar, não vai saber qual *expect* falhou! 😂🤣
{% endhint %}

## Indo os *extra miles*

### Será se precisamos do encadeamento entre o mock e spy? &#x20;

É resposta é não, contudo, no caso do Mongoose, vamos precisar devido ao funcionamento interno do Mongo, em forma de *queries*.

O código abaixo faz o mesmo, contudo separa cada atividade. Para iniciantes, como eu, eu sugiro usar notações como essa, aberta, onde sabemos onde esta o mock, e onde está o spy.&#x20;

```javascript
test('Estamos testando se conseguimos mocar depois de espiar, versão 2', () => {

    const spy = jest.spyOn(video, 'play');
    video.play.mockImplementation(scalar => 42 + scalar);

    const isPlaying = video.play(10);


    expect(spy).toHaveBeenCalled();// gera o mesmo resultado
    expect(isPlaying).toBe(52); // gera o mesmo resultado


});

```

### Será se o spy realmente funciona

Eu gosto muito da curiosidade, mesmo que seja o óbvio.&#x20;

```javascript
test('Testando se o spy realmente sabe que foi chamado', () => {
    const spy = jest.spyOn(video, 'play');
    video.greeting();
    expect(spy).not.toHaveBeenCalled();//vai passar, 
    //o método play nunca foi chamado
});

```

### Testando uma cadeia de métodos

Quando comecei a estudar mock/stubs, tive dificuldades de entender a diferença, as definições pareciam apontar para a mesma coisa, até que li o livro de Christian Johansen.  Esse autor separa claramente o monitoramento do comportamento vs. estado.&#x20;

O problema, como vamos ver no caso do Jest, é que nem sempre é linear essa transformação entre teoria e ferramenta. Por isso defendo de programador ler, para não ficar amarrado a nenhum framework.  Conhecimento flui, ferramentas vai e vem.&#x20;

No nosso caso, o que dificultou meu entendimento do Jest, é que precisamos misturar mock com spy para ter o efeito que Christian Johansen chama de *behavior verification.* Acho que isso seria o famoso mock, e *state verification* seria o stub; mesmo que esteja errado nessa associação, achei fácil de lembrar e desligar meu cérebro de ficar disparando, quando não entendo algo.&#x20;

```javascript
test('See if add was properly called from dispersion', () => {

    const spy = jest.spyOn(functions, 'add').mockImplementation((a, b) => a + b);
    functions.dispersion(2, 2);
    expect(spy.mock.calls[0][1]).toBe(2);//double check if the argument was properly called
})

```

```javascript
const functions =
{
    add: (a, b) => a + b,
    average: (a, b) => functions.add(a, b) / 2,
    dispersion: (a, b) => (functions.average(a, b) - a) / b
}

```

{% hint style="info" %}
Note que o método *dispersion* está dentro de uma cadeia de método&#x73;*.*
{% endhint %}

![Espiando e mocando métodos em cadeia com o Jest](/files/-MdSO76GZFEk8mYqi6H6)

{% hint style="info" %}
Códigos [aqui](https://github.com/JorgeGuerraPires/curso-mongoose/tree/mock_spy_2).
{% endhint %}

{% hint style="info" %}
Livro mencionado Test-Driven JavaScript Development By Christian Johansen · 2010.&#x20;
{% endhint %}

{% hint style="info" %}
Abri uma discussão no Stack Overflow [aqui](https://stackoverflow.com/questions/68193736/mocking-just-one-function-on-a-function-array-using-jest).

No momento que abri essa discussão, fui votado para baixo (*downvoted*). Quando comecei a usar o Stack Overflow, ficava chateado; agora, depois de ver o que eles votam para baixo, não me sinto mais ofendido. Eu concordo que muito provavelmente essa pessoa é uma "babaca". Eu gosto muito das colocação desse [YouTuber](https://www.youtube.com/watch?v=I_ZK0t9-llo), contudo, ainda acho que o *Stack Overflow*, vale a pena. [Eu sou editor da Wiki](https://pt.wikipedia.org/wiki/Usu%C3%A1rio\(a\):Jorge_Guerra_Pires) por anos, e não foi fácil. Qualquer comunidade online terá esses problemas. Não deixe essas pessoas tiraram o melhor desses fóruns, sempre houve e sempre haverá babacas, agora *e-babacas*.&#x20;
{% endhint %}

![](/files/-MdSLepisrxQO2D3FP-c)

{% embed url="<https://www.youtube.com/watch?t=305s&v=qfpZ_wtbNbQ>" %}
Esse artigo em forma de vídeo
{% endembed %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jorgeguerrabrazil-github.gitbook.io/curso-no-mongoose/um-curso-sintetico-em-jest/spyon.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
