Back

Tests unitaires vs tests d'intégration en JavaScript : Quand utiliser chacun

Tests unitaires vs tests d'intégration en JavaScript : Quand utiliser chacun

Chaque développeur JavaScript se pose la même question lors de la construction d’applications fiables : faut-il écrire plus de tests unitaires ou de tests d’intégration ? Un mauvais choix vous fera soit passer des heures à déboguer des tests fragiles, soit livrer des bugs en production. La réponse ne consiste pas à choisir l’un plutôt que l’autre, mais à comprendre quand chaque type apporte le plus de valeur.

Cet article clarifie les différences entre les tests unitaires et d’intégration en JavaScript, vous présente des exemples pratiques de chacun, et fournit un cadre décisionnel pour équilibrer les deux dans votre stratégie de test.

Points clés à retenir

  • Les tests unitaires vérifient des portions de code isolées pour la rapidité et la précision
  • Les tests d’intégration valident les interactions entre composants pour une confiance en conditions réelles
  • Une répartition 70-20-10 (unitaire-intégration-E2E) fonctionne pour la plupart des projets JavaScript
  • Choisissez en fonction de ce que vous testez : les algorithmes nécessitent des tests unitaires, les workflows nécessitent des tests d’intégration

Qu’est-ce qu’un test unitaire ?

Le test unitaire vérifie que des portions individuelles de code fonctionnent correctement de manière isolée. Imaginez cela comme tester une seule brique LEGO avant de l’ajouter à votre structure.

En JavaScript, un test unitaire se concentre généralement sur :

  • Une seule fonction ou méthode
  • Un composant sans ses enfants
  • Une classe ou un module spécifique

Exemple de test unitaire

// calculator.js
export function calculateDiscount(price, percentage) {
  if (percentage < 0 || percentage > 100) {
    throw new Error('Invalid percentage');
  }
  return price * (1 - percentage / 100);
}

// calculator.test.js
import { calculateDiscount } from './calculator';

test('applies 20% discount correctly', () => {
  expect(calculateDiscount(100, 20)).toBe(80);
});

test('throws error for invalid percentage', () => {
  expect(() => calculateDiscount(100, 150)).toThrow('Invalid percentage');
});

Les tests unitaires excellent dans :

  • La rapidité : Quelques millisecondes par test puisqu’il n’y a pas d’I/O ou de dépendances externes
  • La précision : Identifie l’emplacement exact des échecs
  • La stabilité : Se casse rarement à cause de changements non liés

Qu’est-ce qu’un test d’intégration ?

Le test d’intégration vérifie que plusieurs parties de votre application fonctionnent correctement ensemble. Au lieu de tester la brique LEGO seule, vous testez comment plusieurs briques se connectent.

Les tests d’intégration en JavaScript couvrent généralement :

  • Les interactions de composants avec les API
  • Plusieurs modules fonctionnant ensemble
  • Les opérations de base de données avec la logique métier
  • Les composants UI avec la gestion d’état

Exemple de test d’intégration

// userProfile.test.js
import { render, screen, waitFor } from '@testing-library/react';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import UserProfile from './UserProfile';

const server = setupServer(
  rest.get('/api/user/:id', (req, res, ctx) => {
    return res(ctx.json({ 
      id: req.params.id, 
      name: 'Jane Doe',
      role: 'Developer' 
    }));
  })
);

beforeAll(() => server.listen());
afterAll(() => server.close());

test('displays user data after loading', async () => {
  render(<UserProfile userId="123" />);
  
  expect(screen.getByText(/loading/i)).toBeInTheDocument();
  
  await waitFor(() => {
    expect(screen.getByText('Jane Doe')).toBeInTheDocument();
    expect(screen.getByText('Developer')).toBeInTheDocument();
  });
});

Les tests d’intégration fournissent :

  • La confiance : Valide les workflows utilisateur réels
  • La couverture : Teste l’interaction entre les composants
  • La réalité : Détecte les problèmes que les tests unitaires manquent

Différences clés qui comptent

Portée et isolation

Les tests unitaires isolent le code en utilisant des mocks et des stubs. Vous contrôlez chaque variable. Les tests d’intégration utilisent des implémentations réelles dans la mesure du possible, en mockant uniquement les frontières externes comme les API ou les bases de données.

Vitesse d’exécution

Les tests unitaires s’exécutent en 1 à 50 ms chacun. Vous pouvez en exécuter des milliers en quelques secondes. Les tests d’intégration prennent 100 à 500 ms ou plus. Ils impliquent une configuration, un nettoyage et parfois des I/O réelles.

Coût de maintenance

Les tests unitaires se cassent uniquement lorsque leur unité spécifique change. Les tests d’intégration peuvent se casser suite à des changements n’importe où dans le flux testé, nécessitant plus de temps d’investigation.

Détection de bugs

Les tests unitaires détectent les erreurs de logique et les cas limites dans du code isolé. Les tests d’intégration détectent les problèmes de câblage, les hypothèses incorrectes et les violations de contrat entre composants.

Quand utiliser chaque type

Écrivez des tests unitaires pour :

  • Les fonctions pures : Logique métier, calculs, transformations de données
  • Les algorithmes complexes : Tri, recherche, règles de validation
  • Les cas limites : Gestion des erreurs, conditions aux limites
  • Les fonctions utilitaires : Formateurs, parseurs, helpers

Écrivez des tests d’intégration pour :

  • Les interactions API : Requêtes HTTP, gestion des réponses
  • Les workflows utilisateur : Processus multi-étapes, soumissions de formulaires
  • L’intégration de composants : Communication parent-enfant entre composants
  • La gestion d’état : Actions Redux, flux Context API
  • Les opérations de base de données : Opérations CRUD avec logique métier

La stratégie de test pratique

La plupart des projets JavaScript réussis suivent une distribution 70-20-10 :

  • 70 % de tests unitaires : Retour rapide, débogage facile
  • 20 % de tests d’intégration : Confiance dans les interactions entre composants
  • 10 % de tests end-to-end : Validation finale des chemins critiques

Ce n’est pas une règle rigide — ajustez en fonction du type de votre application. Les applications riches en API nécessitent plus de tests d’intégration. Les bibliothèques riches en algorithmes nécessitent plus de tests unitaires.

Intégration dans le pipeline CI/CD

Structurez votre pipeline pour un retour rapide :

  1. Pre-commit : Exécutez les tests unitaires (< 5 secondes)
  2. Pull request : Exécutez tous les tests unitaires et d’intégration
  3. Pre-deploy : Exécutez la suite complète de tests incluant les tests E2E

Des outils comme Jest pour les tests unitaires, Testing Library pour les tests d’intégration, et MSW pour le mocking d’API rendent ce pipeline efficace et maintenable.

Pièges courants à éviter

  1. Sur-mocker dans les tests d’intégration : Annule l’objectif de tester les interactions
  2. Tester les détails d’implémentation : Concentrez-vous sur le comportement, pas sur la structure interne
  3. Ignorer la vitesse des tests : Des tests lents découragent leur exécution fréquente
  4. Écrire des tests après les bugs : Les tests proactifs préviennent les problèmes

Conclusion

Les tests unitaires et d’intégration en JavaScript ne sont pas des stratégies concurrentes — ce sont des outils complémentaires. Les tests unitaires vous donnent rapidité et précision pour la logique isolée. Les tests d’intégration fournissent la confiance que vos composants fonctionnent correctement ensemble.

Commencez par des tests unitaires pour la logique métier et les fonctions pures. Ajoutez des tests d’intégration pour les chemins utilisateur critiques et les interactions entre composants. Évitez les débats religieux sur les philosophies de test et concentrez-vous sur ce qui vous donne confiance pour livrer du code.

La meilleure stratégie de test JavaScript est celle qui détecte les bugs avant les utilisateurs tout en maintenant votre vélocité de développement élevée. Équilibrez les deux types en fonction des besoins de votre application, et ajustez au fur et à mesure que vous apprenez ce qui se casse le plus souvent.

FAQ

Mockez toujours les dépendances externes dans les tests unitaires. Cela inclut les bases de données, les API, les systèmes de fichiers et autres services. Le mocking garantit que les tests s'exécutent rapidement, restent prévisibles et testent vraiment votre code de manière isolée plutôt que le comportement de systèmes externes.

Commencez par vous demander ce qui pourrait se casser. Si la logique elle-même est complexe, écrivez d'abord des tests unitaires. Si la fonctionnalité implique plusieurs composants communiquant entre eux ou des services externes, priorisez les tests d'intégration. La plupart des fonctionnalités bénéficient des deux types.

Les tests unitaires devraient se terminer en moins de 10 secondes pour la suite complète. Les tests d'intégration peuvent prendre 1 à 5 minutes. Si vos tests prennent plus de temps, divisez-les en tâches parallèles ou identifiez les tests lents qui nécessitent une optimisation. Des tests rapides encouragent les développeurs à les exécuter fréquemment.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay