Catégories
Astuces et Design

Tests unitaires dans les applications natives React – Smashing Magazine

A 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…
Plus à propos
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 les 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 découvrir les principes de base du test, explorer différentes bibliothèques pour tester une application et voir comment tester des unités (ou des composants) d'une application React Native. 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 serait d'un grand avantage pendant que vous travaillez dans 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 Button composant et simuler un test unitaire:

import React from 'react';
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
function AppButton({ onPress }) {
    return (
      
          Register
      
    );
}
const styles = StyleSheet.create({
    button: {
        backgroundColor: red;
        borderRadius: 25,
        justifyContent: 'center',
        alignItems: 'center',
    },
    text: {
        color: #fff
    }
})
export default AppButton;

Cette Button le composant contient du texte et un onPress une fonction. 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('renders correctly across screens', () => {
  const tree = renderer.create(

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

Tests unitaires dans les applications natives React

Une application React Native peut être testée avec une variété d'outils, dont certains sont les suivants:

  • WebDriver
    Cet outil de test open-source pour les applications Node.js est également utilisé pour tester les applications React Native.
  • Cauchemar
    Cela 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 des utilisateurs (comme goto, type et click), avec une API qui semble synchrone pour chaque bloc de script, plutôt que des rappels profondément imbriqués. »
  • Plaisanter
    Il s’agit de l’une des bibliothèques de tests les plus populaires et de 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.
  • Moka
    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é de configuration et d'utilisation et de sa rapidité.
  • Jasmin
    Selon sa documentation, Jasmine est un cadre de développement axé sur le comportement pour tester le code JavaScript.

Introduction à la plaisanterie et à l'enzyme

Selon sa documentation, «Jest est un cadre de test JavaScript agréable axé sur la simplicité». Cela fonctionne avec zéro configuration. Lors de l'installation (en utilisant un gestionnaire de packages tel que npm ou Yarn), Jest est prêt à être utilisé, sans aucune autre installation 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 le runtime 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.

Snapshots et configuration Jest

Dans cette section, nous testerons les contacts utilisateur et l'interface utilisateur des composants de l'application en testant des instantanés à l'aide de 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

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

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

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

Ensuite, ajoutez d'autres packages à 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 package.json fichier. D'après la documentation d'Expo React Native, nous devons ajouter un transformIgnorePattern configuration 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 qu'un fichier similaire est trouvé dans le node modules 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 testerons si notre App a un élément enfant dans son arborescence:

import React from "react";
import renderer from "react-test-renderer";
import App from "./App.js"
describe("", () => {
    it('has 1 child', () => {
        const tree = renderer.create().toJSON();
        expect(tree.children.length).toBe(1);
    });
});

Maintenant, cours yarn test ou son équivalent npm. Si App.js a un seul élément enfant, notre test doit 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 le l'arborescence des composants en JSON, puis a demandé à Jest de voir si le nombre retourné de composants enfants dans JSON correspond à ce que nous attendons.

Plus de tests d'instantané

Comme le dit David Adeneye:

«Un test d'instantané 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 qu'il pourrait prendre. »

Cela est fait en particulier lorsqu'un projet implique des styles globaux qui sont utilisés dans de nombreux composants. Écrivons un test d’instantané pour App.js pour tester sa cohérence UI:

it('renders correctly across screens', () => {
  const tree = renderer.create().toJSON();
  expect(tree).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
  √ has 1 child (16ms)
  √ renders correctly (16ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   1 total
Time:        24s

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 moquerie de certaines fonctions de Jest.

Appels d'API moqueurs

D'après la documentation de Jest:

Les fonctions simulées vous permettent de 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 le test- configuration temporelle des valeurs de retour.

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 simulacres nous aident à tester les applications de tant de manières, 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 attachée au composant.

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

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

global.fetch = jest.fn();

// mocking an API success response once
fetch.mockResponseIsSuccess = (body) => {
  fetch.mockImplementationForOnce (
    () => Promise.resolve({json: () => Promise.resolve(JSON.parse(body))})
  );
};

// mocking an API failure response for once
fetch.mockResponseIsFailure = (error) => {
  fetch.mockImplementationForOnce(
    () => Promise.reject(error)
  );
};

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. Elle est similaire à la réponse fictive pour une transaction d'extraction ayant échoué – elle renvoie une erreur.

Ci-dessous le product composant de notre application, contenant un product objet et renvoyer les informations comme props.

import React from 'react';
const Product = () => {
    const product = {
        name: 'Pizza',
        quantity: 5,
        price: '$50'
    }
    return (
        <>
            

Name: {product.name}

Quantity: {product.quantity}

Price: {product.price}

); } export default Product;

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 simuler un composant du produit en utilisant Jest pour décrire les objets du composant.

describe("", () => {
  it("accepts products props", () => {
    const wrapper = mount();
    expect(wrapper.props().product).toEqual(product);
  });
  it("contains products quantity", () => {
    expect(value).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 deuxième test, nous réussissons le customer accessoires pour s'assurer qu'il s'agit d'un produit et qu'il correspond à nos simulacres. Ce faisant, nous n’avons pas à tester tous les composants de notre produit et nous évitons également les bogues dans notre code.

Mocking des demandes d'API externes

Jusqu'à présent, nous avons effectué des tests d'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 se moquer d'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 from 'axios-mock-adapter';
import Faker from 'faker'
import ApiClient from '../constants/api-client';
import userDetails from 'jest/mockResponseObjects/user-objects';

let mockApi = new MockAdapter(ApiClient.getAxiosInstance());
let validAuthentication = {
    name: Faker.internet.email(),
    password: Faker.internet.password()

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

Ici, nous appelons le ApiClient et en lui passant 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 une demande d'API externe. Comme auparavant, nous utiliserons des instantanés.

it('successful sign in with correct credentials', async () => {
  await store.dispatch(authenticateUser('ikechifortune@gmail.com', 'password'));
  expect(getActions()).toMatchSnapshot();
});

it('unsuccessful sign in with wrong credentials', async () => {
  await store.dispatch(authenticateUser('ikechifortune@gmail.com', 'wrong credential'))
  .catch((error) => {
    expect(errorObject).toMatchSnapshot();
  });

Ici, nous testons une connexion réussie avec les informations d'identification correctes, à l'aide du JavaScript natif async await pour retenir nos contributions. Pendant ce temps, le authenticateUser La fonction 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, cours yarn test ou npm test. Je suis sûr que tous vos tests réussiront.

Voyons comment tester des composants dans une bibliothèque de gestion d’états, Redux.

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

Il est indéniable que Redux est l’un des gestionnaires d’états les plus utilisés pour les applications React. La plupart des fonctionnalités de Redux impliquent un dispatch, qui est une fonction du magasin Redux qui permet de déclencher un changement d'état d'une application. Tester Redux peut être délicat car Redux actions croissent 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:

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

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

import mockStore from 'redux-mock-store';
import { LOGOUT } from '../actions/logout';
import User from '../reducers/user';
import { testUser } from 'jest/mock-objects';

  describe('Testing the sign in authentication', () => {
    const store = mockStore();

  it('user attempts with correct password and succeeds', async () => {
  await store.dispatch(authenticateUser('example@gmail.com', 'password'));
  expect(store.getActions()).toMatchSnapshot();
  });
});
  describe('Testing reducers after user LOGS OUT', () => {
    it('user is returned back to initial app state', () => {
      expect(user(testUser, { type: LOGOUT })).toMatchSnapshot();
    });
  });

Dans le premier test, nous décrivons l'authentification de connexion et la création d'un magasin simulé. Nous faisons cela en important d'abord un mockStore à partir de Redux, puis en important une méthode nommée testUser de Jest pour nous aider à se 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
  √ user attempts with correct password and succeeds (23ms)
  √ user is returned back to initial app state (19ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   2 total
Time:        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

Éditorial fracassant(ks, ra, al, il)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *