• 12 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 24/05/2022

Appréhendez la difficulté de tester un appel réseau

Comme tout développeur qui se respecte, vous devriez vous sentir mal à l'aise maintenant... Il y a quelque chose qui vous perturbe fondamentalement, qui secoue votre être tout entier. Et tout à coup, vous posez les mots sur votre inconfort transcendantal :

ON N’A PAS FAIT DE TESTS !

C'est excellent ! Je vois que vous êtes pétri de bonnes pratiques. Mais rassurez-vous, nous allons en parler pendant toute cette partie. Alors, accrochez-vous, car c'est sans doute la partie de ce cours la plus riche !

Identifiez le problème

Comme nous l'avons vu, en MVC on teste au moins le modèle. Donc en l'occurrence, pour nous cela se résume à la classe  QuoteService  .

Or, dans la classe  QuoteService  , on fait des appels réseaux. Et donc, la réponse va tarder à arriver. Et on retombe dans le même problème. On doit attendre la réponse de l'appel dans le test.

Or les tests ne sont pas faits pour attendre. Ils s'exécutent instantanément.

Mais bien sûr, il existe des solutions à cela, et nous allons en mentionner deux :

  1. Les expectations.

  2. Les doubles.

Découvrez le fonctionnement des expectations

Les expectations sont une mécanique présente dans le framework  XCTest  qui permet justement d'attendre un certain délai avant de terminer l'exécution du test.

Voici comment elles fonctionnent :

func testDownloadWebData() {
   // On crée l'expectation en lui donnant une simple description.
    let expectation = XCTestExpectation(description: "Télécharge le site openclassrooms.com")
   // On prépare une requête
   let url = URL(string: "https://openclassrooms.com")!
   let dataTask = URLSession(configuration: .default).dataTask(with: url) { (data, _, _) in
      // On vérifie qu'il y a bien des données qui ont été chargées, c'est ici que le test a lieu.
      XCTAssertNotNil(data)
      // On déclare que l'expectation est terminée, on peut clore le test.
      expectation.fulfill()
   }
   // On lance la requête.
   dataTask.resume()
    // On attend que l'expectation soit terminée, avec une durée maximum de 10 secondes.
   wait(for: [expectation], timeout: 10.0)
}

L'expectation permet d'attendre le retour de la requête. Cette méthode est donc assez simple et a l'avantage de fonctionner tout de suite sans modification du code de notre application.

Mais elle a un très gros défaut : chaque test va mettre entre 2 et 10 secondes, selon la qualité du réseau, à s'exécuter. Ce qui est 50 fois plus long qu'un test classique. Et si vous multipliez ça par 3 ou 4 tests par appel réseau, vous finissez avec une suite de tests qui s'exécute en quelques minutes au lieu de quelques secondes, même pour une petite application.

OK, mais quel est le problème à ce que les tests soient longs ?

Le but des tests est de protéger votre code et d'éviter l'apparition de bugs. Donc à chaque fois que vous changez votre code, vous allez lancer vos tests pour vérifier que tout va bien. Et si vos tests durent à chaque fois quelques minutes, soit vous allez cesser de le faire, soit vous allez perdre un temps fou.

Donc, pour résumer, des tests unitaires longs sont des tests unitaires inexistants.

Par ailleurs, vos tests vont avoir un deuxième défaut, ils seront instables. En fonction de la qualité du réseau, vos tests vont passer ou non. Si la requête met plus de 10 secondes, le test va échouer et vous allez perdre du temps à chercher une erreur qui est en fait simplement due au réseau.

Bref, il faut une autre option : les doubles.

Utilisez les doubles

L'autre option, ce sont les doubles. Un double, c'est une classe qui va se substituer à une autre pour simuler son comportement.

Par exemple, on va créer un double de  URLSession  qui va simuler les appels réseaux, mais ne pas les faire vraiment. On pourra quand même tester le comportement lié à la réponse : s'il manque des données, s'il y a une erreur, si tout va bien, etc. Mais comme on simule l'appel, on n’a pas le délai d'attente de la réponse lié au réseau.

Cette technique permet donc de s'affranchir du délai d'un appel réseau et donc de tous les désavantages qui vont avec, comme la lenteur et l'instabilité des tests. C'est donc largement mieux de procéder ainsi !

Le seul défaut de cette méthode, c'est qu'elle est un peu plus longue à mettre en place. Mais une fois que vous aurez bien compris, ce sera facile !

Nous allons procéder en plusieurs étapes :

  1. Création des réponses réseaux pour simuler le résultat.

  2. Préparation du code pour le rendre testable avec des doubles.

  3. Création du double.

  4. Rédaction des tests.

En résumé

Pour tester des appels réseaux, on peut utiliser :

  • Les expectations : faciles à mettre en place mais rendent les tests lents et instables. Mauvaise option.

  • Les doubles : plus compliqués à mettre en place mais gardent les tests propres et rapides.

Maintenant que vous maîtrisez les expectations et les doubles, rendez-vous dans le prochain chapitre. Nous allons créer des données de test qui vont nous permettre de simuler la réponse à un appel réseau.

Exemple de certificat de réussite
Exemple de certificat de réussite