Fermer

septembre 29, 2020

Tests unitaires dans les applications natives React


À propos de l'auteur

Fortune Ikechi est un ingénieur Frontend basé dans l'État de Rivers au Nigeria. Il est étudiant à l'Université de Port-Harcourt. Il est passionné par la communauté et…
En savoir plus sur
Fortune

Les tests unitaires font désormais partie intégrante du processus de développement logiciel. C'est le niveau de test auquel les composants du logiciel sont testés. Dans ce didacticiel, vous apprendrez à tester des unités d'une application React Native.

React Native est l'un des frameworks les plus utilisés pour créer des applications mobiles. Ce didacticiel est destiné aux développeurs qui souhaitent commencer à tester les applications React Native qu'ils créent. Nous utiliserons le framework de test Jest et Enzyme.

Dans cet article, nous allons apprendre les principes de base du test, explorer diverses bibliothèques pour tester une application et voir comment tester des unités (ou des composants) d'un React Native application. En travaillant avec une application React Native, nous consoliderons nos connaissances en matière de tests.

Remarque: Une connaissance de base de JavaScript et de React Native vous serait très utile au cours de ce didacticiel.

Qu'est-ce que le test unitaire?

Le test unitaire est le niveau de test auquel les composants individuels du logiciel sont testés. Nous le faisons pour nous assurer que chaque composant fonctionne comme prévu. Un composant est la plus petite partie testable du logiciel.

Pour illustrer, créons un composant Button et simulons un test unitaire:

 import React from 'react';
importer {StyleSheet, Text, TouchableOpacity} depuis 'react-native';
function AppButton ({onPress}) {
    revenir (
      
           Registre 
      
    );
}
const styles = StyleSheet.create ({
    bouton: {
        backgroundColor: rouge;
        borderRadius: 25,
        justifyContent: 'centre',
        alignItems: 'centre',
    },
    texte: {
        couleur: #fff
    }
})
exporter AppButton par défaut;

Ce composant Button a du texte et une fonction onPress . Testons ce composant pour voir en quoi consiste le test unitaire.

Commençons par créer un fichier de test, nommé Button.test.js :

 it ('rend correctement à travers les écrans', () => {
  const tree = renderer.create (). toJSON ();
  expect (arbre) .toMatchSnapshot ();
});

Ici, nous testons pour voir si notre composant Button rend comme il se doit sur tous les écrans de l'application. C'est le but des tests unitaires: tester les composants d'une application pour s'assurer qu'ils fonctionnent comme ils le devraient.

Tests unitaires dans les applications React Native

Une application React Native peut être testée avec divers outils, dont certains qui sont les suivants:

  • WebDriver
    Cet outil de test open-source pour les applications Node.js est également utilisé pour tester les applications React Native.
  • Nightmare
    Ceci automatise les opérations de test dans le navigateur. Selon la documentation «l'objectif est d'exposer quelques méthodes simples qui imitent les actions de l'utilisateur (comme goto type et click ), avec une API qui se sent synchrone pour chaque bloc de script, plutôt que des rappels profondément imbriqués. »
  • Jest
    C'est l'une des bibliothèques de test les plus populaires et celle sur laquelle nous allons nous concentrer aujourd'hui. Comme React, il est maintenu par Facebook et a été conçu pour fournir une configuration «zéro config» pour des performances maximales.
  • Mocha
    Mocha est une bibliothèque populaire pour tester les applications React et React Native. Il est devenu un outil de test de choix pour les développeurs en raison de sa facilité d'installation et d'utilisation et de sa rapidité.
  • Jasmine
    Selon sa documentation Jasmine est un comportement-

Introduction à Jest And Enzyme

Selon sa documentation «Jest est un cadre de test JavaScript agréable avec un accent sur la simplicité». Cela fonctionne avec zéro configuration. Lors de l'installation (à l'aide d'un gestionnaire de packages tel que npm ou Yarn), Jest est prêt à être utilisé, aucune autre installation n'est nécessaire.

Enzyme est un framework de test JavaScript pour les applications React Native. (Si vous travaillez avec React plutôt qu'avec React Native, un guide est disponible .) Nous utiliserons Enzyme pour tester les unités de sortie de notre application. Avec lui, nous pouvons simuler l’exécution de l’application.

Commençons par configurer notre projet. Nous utiliserons l'application Done With It sur GitHub. Il s’agit d’une place de marché d’applications React Native. Commencez par le cloner, accédez au dossier et installez les packages en exécutant ce qui suit pour npm…

 npm install

… ou ceci pour Yarn:

 yarn install

Cette commande installera tous les packages de notre application. Une fois cela fait, nous testerons la cohérence de l'interface utilisateur de notre application à l'aide d'instantanés, décrits ci-dessous.

Configuration des instantanés et des plaisanteries

Dans cette section, nous testerons les contacts utilisateur et l'interface utilisateur des composants de l'application en testant des instantanés à l'aide Jest.

Avant de faire cela, nous devons installer Jest et ses dépendances. Pour installer Jest pour Expo React Native, exécutez la commande suivante:

 yarn add jest-expo --dev

Ceci installe jest-expo dans le répertoire de notre application. Ensuite, nous devons mettre à jour notre fichier package.json pour avoir un script de test:

 "scripts": {
    "test" "plaisanterie"
},
"plaisanterie": {
    "preset": "jest-expo"
}

En ajoutant cette commande, nous indiquons à Jest quel paquet enregistrer dans notre application et où.

Ensuite, ajoutons d'autres paquets à notre application qui aideront Jest à faire un test complet. Pour npm, exécutez ceci…

 npm i react-test-renderer --save-dev

… et pour Yarn, ceci:

 yarn add react-test-renderer --dev

Nous avons encore une petite configuration à faire dans notre fichier package.json . Selon la documentation d'Expo React Native nous devons ajouter une configuration transformIgnorePattern qui empêche les tests de s'exécuter dans Jest chaque fois qu'un fichier source correspond à un test (c'est-à-dire si un test est effectué et un fichier se trouve dans les modules de nœuds du projet).

 "jest": {
  "preset": "jest-expo",
  "transformIgnorePatterns": [
    "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@sentry/.*)"
  ]
}

Maintenant, créons un nouveau fichier, nommé App.test.js pour écrire notre premier test. Nous allons tester si notre App a un élément enfant dans son arborescence:

 import React de "react";
importer le rendu depuis "react-test-renderer";
importer l'application depuis "./App.js"
décrire ("", () => {
    it ('a 1 enfant', () => {
        const tree = renderer.create (). toJSON ();
        expect (tree.children.length) .toBe (1);
    });
});

Maintenant, lancez le test de fil ou son équivalent npm. Si App.js a un seul élément enfant, notre test devrait réussir, ce qui sera confirmé dans l'interface de ligne de commande.

Dans le code ci-dessus, nous avons importé React et react-test-renderer qui rend nos tests pour Expo . Nous avons converti l'arborescence des composants en JSON, puis demandé à Jest de voir si le nombre renvoyé de composants enfants dans JSON correspond à ce que nous attendons.

Plus de tests d'instantané

Comme David Adeneye déclare :

«Un test de capture instantanée garantit que l'interface utilisateur (UI) d'une application Web ne change pas de manière inattendue. Il capture le code d'un composant à un moment donné, afin que nous puissions comparer le composant dans un état avec n'importe quel autre état possible. »

Ceci est fait en particulier lorsqu'un projet implique des styles globaux qui sont utilisés à travers beaucoup de composants. Écrivons un test d'instantané pour App.js pour tester la cohérence de l'interface utilisateur:

 it ('rend correctement à travers les écrans', () => {
  const tree = renderer.create (). toJSON ();
  expect (arbre) .toMatchSnapshot ();
});
 

Ajoutez ceci aux tests que nous avons déjà écrits, puis exécutez yarn test (ou son équivalent npm). Si notre test réussit, nous devrions voir ceci:

 PASS src / App.test.js
  √ a 1 enfant (16 ms)
  √ rend correctement (16ms)

Suites de tests: 1 réussie, 1 au total
Tests: 2 réussis, 2 au total
Instantanés: 1 au total
Temps: 24 s

Cela nous indique que nos tests ont réussi et le temps qu'ils ont pris. Votre résultat sera similaire si les tests réussissent.

Passons à la dérision de certaines fonctions de Jest.

Appels moqueurs d'API

D'après la documentation de Jest :

Les fonctions simulées vous permettent pour tester les liens entre le code en effaçant l'implémentation réelle d'une fonction, en capturant les appels à la fonction (et les paramètres passés dans ces appels), en capturant les instances de fonctions du constructeur lorsqu'elles sont instanciées avec `new`, et en permettant la configuration de retour au moment du test

En termes simples, une maquette est une copie d'un objet ou d'une fonction sans le fonctionnement réel de cette fonction. Il imite cette fonction.

Les simulations nous aident à tester des applications de tant de façons, mais le principal avantage est qu'elles réduisent notre besoin de dépendances.

Les simulations peuvent généralement être effectuées de deux manières. La première consiste à créer une fonction fictive qui est injectée dans le code à tester. L'autre consiste à écrire une fonction fictive qui remplace le package ou la dépendance qui est attaché au composant.

La plupart des organisations et développeurs préfèrent écrire des simulations manuelles qui imitent les fonctionnalités et utilisent de fausses données pour tester certains composants.

React Native inclut fetch dans l'objet global. Pour éviter de faire de vrais appels d'API dans notre test unitaire, nous nous en moquons. Voici un moyen de se moquer de tous, sinon la plupart, de nos appels d'API dans React Native, et sans avoir besoin de dépendances:

 global.fetch = jest.fn ();

// se moquer d'une réponse de réussite d'API une fois
fetch.mockResponseIsSuccess = (corps) => {
  fetch.mockImplementationForOnce (
    () => Promise.resolve ({json: () => Promise.resolve (JSON.parse (corps))})
  );
};

// se moquer d'une réponse d'échec d'API pour une fois
fetch.mockResponseIsFailure = (erreur) => {
  fetch.mockImplementationForOnce (
    () => Promise.reject (erreur)
  );
};

Ici, nous avons écrit une fonction qui essaie de récupérer une API une fois. Après avoir fait cela, il renvoie une promesse et, une fois résolue, il renvoie le corps en JSON. C'est similaire à la réponse fictive pour une transaction d'extraction qui a échoué – elle renvoie une erreur.

Ci-dessous se trouve le composant product de notre application, contenant un objet product et renvoyant les informations sous la forme accessoires .

 import React de 'react';
const Produit = () => {
    produit const = {
        nom: 'Pizza',
        quantité: 5,
        prix: '50 $'
    }
    revenir (
        <>
            

Nom: {product.name}

Quantité: {product.quantity}

Price: {product.price}

> ); } exporter le produit par défaut;

Imaginons que nous essayions de tester tous les composants de notre produit. L'accès direct à notre base de données n'est pas une solution envisageable. C'est là que les moqueries entrent en jeu. Dans le code ci-dessous, nous essayons de nous moquer d'un composant du produit en utilisant Jest pour décrire les objets du composant.

 describe ("", () => {
  it ("accepte les produits props", () => {
    wrapper const = montage ();
    expect (wrapper.props (). produit) .toEqual (produit);
  });
  it ("contient la quantité de produits", () => {
    expect (valeur) .toBe (3);
  });
});

Nous utilisons describe de Jest pour dicter les tests que nous voulons faire. Dans le premier test, nous vérifions si l'objet que nous passons est égal aux accessoires dont nous nous sommes moqués.

Dans le second test, nous passons les accessoires client pour nous en assurer est un produit et qu'il correspond à nos simulations. Ce faisant, nous n'avons pas à tester tous les composants de notre produit et nous évitons également les bogues dans notre code.

Mocking External API Requests

Jusqu'à présent, nous avons exécuté des tests pour les appels d'API avec d'autres éléments de notre application. Maintenant, simulons un appel d'API externe. Nous allons utiliser Axios. Pour tester un appel externe à une API, nous devons nous moquer de nos demandes et également gérer les réponses que nous obtenons. Nous allons utiliser axios-mock-adapter pour simuler Axios. Tout d'abord, nous devons installer axios-mock-adapter en exécutant la commande ci-dessous:

 yarn add axios-mock-adapter

La prochaine chose à faire est de créer nos simulacres:

 import MockAdapter depuis 'axios-mock-adapter';
importer Faker depuis 'faker'
importer ApiClient depuis '../constants/api-client';
importer des détails utilisateur depuis 'jest / mockResponseObjects / user-objects';

let mockApi = new MockAdapter (ApiClient.getAxiosInstance ());
laissez validAuthentication = {
    nom: Faker.internet.email (),
    mot de passe: Faker.internet.password ()

mockApi.onPost ('requests'). reply (config) => {
  if (config.data === validAuthentication) {
      retour [200, userDetails];
    }
  retour [400, 'Incorrect username and password'];
 });

Ici, nous appelons le ApiClient et lui passons une instance Axios pour se moquer des informations d'identification de l'utilisateur. Nous utilisons un package nommé faker.js pour générer de fausses données utilisateur, telles qu'une adresse e-mail et un mot de passe.

Le simulacre se comporte comme nous l'attendons de l'API. Si la demande aboutit, nous recevrons une réponse avec un code d'état de 200 pour OK. Et nous obtiendrons un code de statut de 400 pour une mauvaise requête au serveur, qui sera envoyée avec JSON avec le message "Nom d'utilisateur et mot de passe incorrects".

Maintenant que notre maquette est prête, écrivons un test pour un demande d'API externe. Comme auparavant, nous utiliserons des instantanés.

 it ('connexion réussie avec les informations d'identification correctes', async () => {
  attendre store.dispatch (authenticateUser ('ikechifortune@gmail.com ',' mot de passe '));
  expect (getActions ()). toMatchSnapshot ();
});

it ('échec de la connexion avec des informations d'identification incorrectes', async () => {
  attendre store.dispatch (authenticateUser ('ikechifortune@gmail.com ',' faux identifiant '))
  .catch ((erreur) => {
    expect (errorObject) .toMatchSnapshot ();
  });

Ici, nous testons une connexion réussie avec les informations d'identification correctes, en utilisant le JavaScript natif async wait pour conserver nos entrées. Pendant ce temps, la fonction authenticateUser de Jest authentifie la demande et s'assure qu'elle correspond à nos instantanés précédents. Ensuite, nous testons une connexion infructueuse en cas d'informations d'identification erronées, telles que l'adresse e-mail ou le mot de passe, et nous envoyons une erreur en réponse.

Maintenant, exécutez yarn test ou test npm . Je suis sûr que tous vos tests réussiront.

Voyons comment tester les composants d'une bibliothèque de gestion d'état, Redux.

Test des actions et des réducteurs Redux à l'aide de snapshots

On ne peut nier que Redux est l'un des les gestionnaires d'état les plus utilisés pour les applications React. La plupart des fonctionnalités de Redux impliquent un envoi qui est une fonction du magasin Redux utilisé pour déclencher un changement d'état d'une application. Tester Redux peut être délicat car les actions de Redux augmentent rapidement en taille et en complexité. Avec les instantanés Jest, cela devient plus facile. La plupart des tests avec Redux se résument à deux choses:

  • Pour tester les actions nous créons redux-mock-store et expédions les actions.
  • Pour tester les réducteurs, nous importons le réducteur et lui passer un état et un objet d'action.

Voici un test Redux avec des instantanés. Nous testerons les actions envoyées en authentifiant l'utilisateur à l'adresse SIGN-IN et en voyant comment l'action LOGOUT est gérée par le réducteur user .

 import mockStore de 'redux-mock-store';
import {LOGOUT} depuis '../actions/logout';
importer un utilisateur depuis '../reducers/user';
import {testUser} depuis 'jest / mock-objects';

  describe ('Test de l'authentification de connexion', () => {
    const store = mockStore ();

  it ('l'utilisateur tente avec le mot de passe correct et réussit', async () => {
  Wait store.dispatch (authenticateUser ('example@gmail.com ',' password '));
  expect (store.getActions ()). toMatchSnapshot ();
  });
});
  describe ('Test des réducteurs après la déconnexion de l'utilisateur', () => {
    it ('l'utilisateur est renvoyé à l'état initial de l'application', () => {
      expect (utilisateur (testUser, {type: LOGOUT})). toMatchSnapshot ();
    });
  });

Dans le premier test, nous décrivons l'authentification par connexion et créons un magasin simulé. Nous faisons cela en important d'abord un mockStore de Redux, puis en important une méthode nommée testUser de Jest pour nous aider à nous moquer d'un utilisateur. Ensuite, nous testons le moment où l'utilisateur se connecte avec succès à l'application en utilisant une adresse e-mail et un mot de passe qui correspondent à ceux de notre magasin de snapshots. Ainsi, l'instantané garantit que les objets que l'utilisateur saisit correspondent à chaque fois qu'un test est exécuté.

Dans le deuxième test, nous testons le moment où l'utilisateur se déconnecte. Une fois que notre instantané du réducteur confirme qu'un utilisateur s'est déconnecté, il revient à l'état initial de l'application.

Ensuite, nous testons en exécutant yarn test . Si les tests ont réussi, nous devrions voir le résultat suivant:

 PASS src / redux / actions.test.js
  √ l'utilisateur tente avec le mot de passe correct et réussit (23 ms)
  √ l'utilisateur est renvoyé à l'état initial de l'application (19 ms)

Suites de tests: 1 réussie, 1 au total
Tests: 2 réussis, 2 au total
Instantanés: 2 au total
Temps: 31s

Conclusion

Avec Jest, tester les applications React Native n'a jamais été aussi simple, en particulier avec les instantanés, qui garantissent que l'interface utilisateur reste cohérente quels que soient les styles globaux. De plus, Jest nous permet de nous moquer de certains appels et modules d'API dans notre application. Nous pouvons aller plus loin en testant les composants d'une application React Native.

Autres ressources

 Smashing Editorial (ks, ra, al, il)




Source link