Tests en Swift : Unit, Integration, E2E — guide complet

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Test en Swift : Unit, Intégration, E2E — de la théorie à la pratique



Un test de qualité n'est pas simplement une « bonne pratique » dans le développement iOS et macOS, mais une étape cruciale qui garantit la stabilité, la sécurité et la prévisibilité d'une application. Dans cet article, nous allons décomposer les trois niveaux de test en Swift : Tests Unitaires, Tests d'Intégration et Tests E2E (end-to-end). Vous découvrirez leurs différences, quand les utiliser et comment écrire des tests efficaces avec les frameworks XCTest et XCUITest.



1. Tests Unitaires : vérifier les « briques » de l'application



Les tests unitaires sont le type de test le plus bas niveau et le plus rapide. Ils vérifient le fonctionnement de fonctions, méthodes ou classes individuelles (unités) isolées des dépendances externes (réseau, base de données, UI).



Principes fondamentaux des tests unitaires en Swift :

  • Isolation : le code testé ne doit pas dépendre de l'état d'autres modules.
  • Répétabilité : le test doit donner le même résultat à chaque exécution.
  • Rapidité : des milliers de tests unitaires doivent s'exécuter en quelques secondes.


Exemple de test unitaire avec XCTest :

import XCTest

class Calculator { func add(_ a: Int, _ b: Int) -> Int { return a + b } func divide(_ a: Int, _ b: Int) throws -> Int { guard b != 0 else { throw CalculationError.divisionByZero } return a / b }}

enum CalculationError: Error { case divisionByZero}

class CalculatorTests: XCTestCase { var calculator: Calculator! override func setUp() { super.setUp() calculator = Calculator() } override func tearDown() { calculator = nil super.tearDown() } func testAddition() { // Given let a = 5 let b = 3 // When let result = calculator.add(a, b) // Then XCTAssertEqual(result, 8, "5 + 3 doit être égal à 8") } func testDivisionByZeroThrowsError() { // Utilisation de XCTAssertThrowsError pour vérifier les exceptions XCTAssertThrowsError(try calculator.divide(10, 0)) { error in XCTAssertEqual(error as? CalculationError, .divisionByZero) } }}


Bonnes pratiques pour les tests unitaires :

  • Utilisez le modèle AAA (Arrange-Act-Assert) — préparation, action, vérification.
  • Nommez les tests de manière significative : testMethodName_condition_expectedResult.
  • Évitez de tester les méthodes privées — testez l'interface publique.
  • Pour les mocks et les stubs, utilisez des protocoles et l'injection de dépendances.


2. Tests d'Intégration : vérifier l'interaction des composants



Les tests d'intégration vérifient comment les différents modules d'une application fonctionnent ensemble. Dans le contexte iOS, il peut s'agir de l'interaction d'une ViewModel avec le réseau, Core Data ou UserDefaults.



Exemple de test d'intégration avec un mock de la couche réseau :

import XCTest

// Protocole pour le service réseau (permet une substitution facile)protocol NetworkServiceProtocol { func fetchUser(id: Int, completion: @escaping (Result<User, Error>) -> Void)}

// Service réel (non testé dans le test d'intégration)class RealNetworkService: NetworkServiceProtocol { func fetchUser(id: Int, completion: @escaping (Result<User, Error>) -> Void) { // Requête HTTP réelle }}

// Service Mock pour les testsclass MockNetworkService: NetworkServiceProtocol { var shouldReturnError = false var mockUser = User(id: 1, name: "Test User") func fetchUser(id: Int, completion: @escaping (Result<User, Error>) -> Void) { if shouldReturnError { completion(.failure(NSError(domain: "test", code: 500)))

Blogs

Book Recommendations