# Testing

L'unit-testing n'est pas optionnel.

Avec un langage dynamiquement typé comme le JavaScript, si la couverture de code par les tests n'est pas suffisante, nous ne sommes même pas à l'abris des erreurs de syntaxe.

{% hint style="warning" %}
Pas de tests unitaires\
\=> pas de refactoring & pas d'update de dépendances\
\=> dette technique & régression perpétuelle\
\=> peur du changement\
\=> vélocité 0
{% endhint %}

{% hint style="info" %}
Les tests unitaires permettent de localiser immédiatement les sources des erreurs.
{% endhint %}

**Les tests unitaires doivent être implémentés en premier.**

<https://guide-agile.wishtack.io/extreme-programming/testing>

{% embed url="<https://guide-agile.wishtack.io/extreme-programming/testing>" %}

La modularité facilite l'implémentation des tests unitaires.

## Les Outils

Il existe plusieurs frameworks et outils pour implémenter les tests unitaires Node.js

Les frameworks les plus utilisés sont Jasmine et Mocha. Ceux-ci étant très similaires, il est recommandé d'utiliser Jasmine qui permet également d'implémenter les tests Angular.

<http://thejsguy.com/2015/01/12/jasmine-vs-mocha-chai-and-sinon.html>

{% embed url="<http://thejsguy.com/2015/01/12/jasmine-vs-mocha-chai-and-sinon.html>" %}

\
<http://jasmine.github.io/>

{% embed url="<http://jasmine.github.io/>" %}

<https://mochajs.org/>

{% embed url="<https://mochajs.org/>" %}

<https://jestjs.io/>

{% embed url="<https://jestjs.io/>" %}

## Jasmine

### Exemple avec Jasmine

```javascript
const cache = require('cache');
const User = require('user');
const Wish = require('wish');

describe('User', () => {

    beforeEach(() => {
        cache.clear();
    });

    afterEach(() => {
        cache.clear();
    });

    it('should add wishes', function() {

        const user = new User();
        const wish = new Wish({title: 'Holidays'});

        /* Add a wish. */
        user.addWish(wish);

        /* Check wishlist. */
        expect(user.wishList().length).toEqual(1);
        expect(user.wishList()[0].title()).toEqual('Holidays');

    });

});
```

### Exécution des tests avec `jasmine-node`

```javascript
yarn add --dev jasmine-node

yarn jasmine-node --autoTest --watchFolders app.js routes views test/unit
```

### Jasmine's Spies

Les *spies* de Jasmine sont une implémentation de *mocks*.

Ils permettent d'implémenter des tests comportementaux. Autrement dit, ils permettent de simuler le comportement d'une partie de code que l'on souhaite exclure du test unitare.

Sans *mocks*, les tests seraient des tests d'intégration et non des tests unitaires.

```javascript
describe('SearchEngine', () => {

    it('should pass locale to third party api', () => {

        /* Spying on `thirdPartySearchApi.search` and faking result. */
        spyOn(thirdPartySearchApi, 'search').and.returnValue([
            {
                title: 'Wishtack - Making Your Wishes Come True',
                url: 'https://www.wishtack.com'
            }
        ]);

        /* Trigger search. */
        searchEngine.search({keywords: 'Wishtack'});

        /* Check spy's call count. */
        expect(thirdPartySearchApi.search.callCount).toBe(1);

        /* Check spy's call args. */
        expect(thirdPartySearchApi.search).toHaveBeenCalledWith({
            country: 'US',
            keywords: 'Wishtack',
            language: 'en'
        });

    });

});
```

{% hint style="warning" %}
Pensez à tester les cas d'erreur !
{% endhint %}

## **HTTP Testing**

Pour tester le *routing* et les interactions avec le serveur, il faut simuler les requêtes à l'aide d'outils comme `supertest`.

**<https://github.com/visionmedia/supertest>**

{% embed url="<https://github.com/visionmedia/supertest>" %}

```javascript
const express = require('express');
const request = require('supertest');

describe('wishes RESTful API', () => {

    it('should return wishes', (done) => {

        request(app)
            .get('/users/123456/wishes/')
            .set('Accept', 'application/json')
            .expect(200, [
                {
                    id: 'abcdef',
                    title: 'Holidays'
                }
            ], done);

    });
    
});
```
