paint-brush
Logiciel stable : découvrez la puissance des tests automatiséspar@igorluchenkov
1,022 lectures
1,022 lectures

Logiciel stable : découvrez la puissance des tests automatisés

par Igor Luchenkov6m2024/03/02
Read on Terminal Reader

Trop long; Pour lire

Les tests automatisés sont un moyen de tester votre logiciel sans y consacrer trop de temps. Il existe trois types de tests : unitaires, d'intégration et de bout en bout. Examinons en profondeur chaque type et comprenons pourquoi nous avons besoin de chacun. Les tests unitaires sont rapides. L'isolation leur permet de les exécuter à tout moment, localement et sur CI, sans lancer les services dépendants/effectuer des appels d'API et de base de données. Les tests d'intégration sont plus lents, mais ils testent la façon dont les parties de votre application se connectent.
featured image - Logiciel stable : découvrez la puissance des tests automatisés
Igor Luchenkov HackerNoon profile picture

Cet article mérite votre attention si vous

  • Vous êtes passionné par l’écriture de logiciels de bonne qualité et souhaitez améliorer la stabilité de votre application avec des tests.


  • Vous en avez assez des bugs inattendus qui apparaissent dans vos systèmes de production.


  • Besoin d'aide pour comprendre ce que sont les tests automatisés et comment les aborder.

Pourquoi avons-nous besoin de tests automatisés ?

En tant qu'ingénieurs, nous voulons créer des choses qui fonctionnent , mais à chaque nouvelle fonctionnalité que nous créons, nous augmentons inévitablement la taille et la complexité de nos applications.


À mesure que le produit se développe, il devient de plus en plus long de tester manuellement (par exemple avec vos mains) chaque fonctionnalité affectée par vos modifications.


L'absence de tests automatisés nous amène soit à passer trop de temps et à ralentir notre vitesse d'expédition, soit à dépenser trop peu pour économiser la vitesse, ce qui entraîne de nouveaux bugs dans le backlog ainsi que les appels de fin de soirée de PagerDuty.


Au contraire, les ordinateurs peuvent être programmés pour faire la même chose à plusieurs reprises . Alors déléguons les tests aux ordinateurs !


Types de tests

Pyramide de tests


L' idée de la pyramide des tests suggère trois types principaux de tests : unitaires, d'intégration et de bout en bout . Examinons en profondeur chaque type et comprenons pourquoi nous avons besoin de chacun.

Tests unitaires

Une unité est un petit élément logique que vous testez de manière isolée (sans compter sur d'autres composants).

Les tests unitaires sont rapides. Ils terminent en quelques secondes. L'isolation leur permet de les exécuter à tout moment, localement et sur CI, sans lancer les services dépendants/effectuer des appels d'API et de base de données.


Exemple de test unitaire : une fonction qui accepte deux nombres et les additionne. Nous voulons l'appeler avec différents arguments et affirmer que la valeur renvoyée est correcte.


 // Function "sum" is the unit const sum = (x, y) => x + y test('sums numbers', () => { // Call the function, record the result const result = sum(1, 2); // Assert the result expect(result).toBe(3) }) test('sums numbers', () => { // Call the function, record the result const result = sum(5, 10); // Assert the result expect(result).toBe(15) })


Un exemple plus intéressant est le composant React qui restitue du texte une fois la requête API terminée. Nous devons nous moquer du module API pour renvoyer les valeurs nécessaires à nos tests, restituer le composant et affirmer que le code HTML rendu contient le contenu dont nous avons besoin.


 // "MyComponent" is the unit const MyComponent = () => { const { isLoading } = apiModule.useSomeApiCall(); return isLoading ? <div>Loading...</div> : <div>Hello world</div> } test('renders loading spinner when loading', () => { // Mocking the API module, so that it returns the value we need jest.mock(apiModule).mockReturnValue(() => ({ useSomeApiCall: jest.fn(() => ({ // Return "isLoading: false" for this test case isLoading: false })) })) // Execute the unit (render the component) const result = render(<MyComponent />) // Assert the result result.findByText('Loading...').toBeInTheDocument() }) test('renders text content when not loading', () => { // Mocking the API module jest.mock(apiModule).mockReturnValue(() => ({ useSomeApiCall: jest.fn(() => ({ // Return "isLoading: false" for this test case isLoading: false })) })) // Execute the unit (render the component) const result = render(<MyComponent />) // Assert the result result.findByText('Hello world').toBeInTheDocument() })


Tests d'intégration

Lorsque votre unité interagit avec d’autres unités (dépendances) , nous appelons cela une intégration . Ces tests sont plus lents que les tests unitaires, mais ils testent la manière dont les parties de votre application se connectent.


Exemple de test d'intégration : Un service qui crée des utilisateurs dans une base de données. Cela nécessite qu'une instance de base de données ( dépendance ) soit disponible lors de l'exécution des tests. Nous testerons que le service peut créer et récupérer un utilisateur depuis la base de données.


 import db from 'db' // We will be testing "createUser" and "getUser" const createUser = name => db.createUser(name) // creates a user const getUser = name => db.getUserOrNull(name) // retrieves a user or null test("creates and retrieves users", () => { // Try to get a user that doesn't exist, assert Null is returned const nonExistingUser = getUser("i don't exist") expect(nonExistingUser).toBe(null); // Create a user const userName = "test-user" createUser(userName); // Get the user that was just created, assert it's not Null const user = getUser(userName); expect(user).to.not.be(null) })


Tests de bout en bout

Il s'agit d'un test de bout en bout lorsque nous testons l' application entièrement déployée , où toutes ses dépendances sont disponibles. Ces tests simulent au mieux le comportement réel de l'utilisateur et vous permettent de détecter tous les problèmes possibles dans votre application, mais il s'agit du type de test le plus lent .


Chaque fois que vous souhaitez exécuter des tests de bout en bout, vous devez provisionner toute l'infrastructure et vous assurer que des fournisseurs tiers sont disponibles dans votre environnement.


Vous souhaitez uniquement les disposer pour les fonctionnalités critiques de votre application.


Jetons un coup d'œil à un exemple de test de bout en bout : flux de connexion. Nous voulons accéder à l'application, remplir les informations de connexion, la soumettre et voir le message de bienvenue.


 test('user can log in', () => { // Visit the login page page.goto('https://example.com/login'); // Fill in the login form page.fill('#username', 'john'); page.fill('#password', 'some-password'); // Click the login button page.click('#login-button'); // Assert the welcome message is visible page.assertTextVisible('Welcome, John!') })

Comment choisir le type de test à rédiger ?

N'oubliez pas que les tests de bout en bout sont plus lents que l'intégration et que les tests d'intégration sont plus lents que les tests unitaires .


Si la fonctionnalité sur laquelle vous travaillez est critique, envisagez d'écrire au moins un test de bout en bout (par exemple, vérifier le fonctionnement de la fonctionnalité de connexion lors du développement du flux d'authentification).


Outre les flux critiques, nous souhaitons tester autant de cas extrêmes et différents états de la fonctionnalité que possible. Les tests d'intégration nous permettent de tester comment les parties de l'application fonctionnent ensemble.


Avoir des tests d'intégration pour les points finaux et les composants clients est une bonne idée. Les points de terminaison doivent effectuer les opérations, produire le résultat attendu et ne générer aucune erreur inattendue.


Les composants clients doivent afficher le contenu correct et répondre aux interactions des utilisateurs avec la façon dont vous attendez qu'ils réagissent.


Et enfin, quand faut-il choisir les tests unitaires ? Toutes les petites fonctions qui peuvent être testées isolément, telles que sum qui additionne les nombres, Button qui restitue la balise <button> , sont d'excellents candidats pour les tests unitaires. Les unités sont parfaites si vous suivez l’approche Test Driven Development .


Et après?

Écrivez des tests ! (mais commencez petit)

  • Installez un framework de test adapté à votre projet/langage. Chaque langage dispose d'une bibliothèque populaire pour les tests, telle que Jest / Vitest pour JavaScript, Cypress / Playwright pour de bout en bout (utilise également JavaScript), JUnit pour Java, etc.


  • Trouvez une petite fonction dans votre projet et écrivez un test unitaire pour celle-ci.


  • Écrivez un test d'intégration pour une interaction composant/service-base de données.


  • Choisissez un scénario critique qui peut être rapidement testé, tel qu'un simple flux de connexion, et écrivez un test de bout en bout pour cela.


Faites les choses ci-dessus une fois pour comprendre comment cela fonctionne. Ensuite, recommencez pendant certains travaux sur les fonctionnalités/bugs. Partagez-le ensuite avec vos collègues pour que vous puissiez tous passer des tests, gagner du temps et mieux dormir la nuit !


Ressources utiles :