Après avoir créé votre fichier ViewModel, nous allons développer un fichier de test unitaire pour en assurer sa robustesse.
Initialisez le fichier de test unitaire
Voici une vidéo qui montre les principales étapes pour initier le fichier de test unitaire du ViewModel.
Comprenez l'importance des tests unitaires
Nous en avons déjà un peu parlé mais les tests unitaires sont essentiels dans le développement logiciel pour plusieurs raisons :
Que ça soit dans le cadre d’une refactorisation ou non, ils permettent de vérifier que chaque partie du code fonctionne comme prévu.
En ajoutant des tests unitaires pour chaque nouvelle fonctionnalité, vous vous assurez que les modifications futures ne casseront pas les fonctionnalités existantes.
Ils servent de documentation sur ce que le code est censé faire.
Dans le contexte de l'architecture MVVM, les tests unitaires sont particulièrement importants pour les ViewModels. Ils assurent que la logique de présentation et d'interaction de votre application fonctionne correctement de manière isolée. Cela améliore grandement la qualité et la fiabilité de l'application.
Initiez le fichier de test unitaire dans Xcode
Pour créer le fichier de test unitaire, il faut suivre les étapes suivantes.
Ajoutez un nouveau fichier de test.
Sélectionnez le dossier du projet dans le navigateur de projet.
Cliquez sur Fichier dans la barre de menu, puis sélectionnez Nouveau et Fichier….
Dans la fenêtre qui s'ouvre, choisissez Test unitaire sous la section iOS et cliquez surSuivant.
Nommez le fichier de test.
Donnez un nom descriptif à votre fichier de test, tel que “HomeViewModelTests”.
Assurez-vous que le fichier est ajouté à la bonne cible de test et cliquez sur Créer.
Exécutez les tests à vide.
Appuyez sur les touchescommand + U pour exécuter tous les tests.
Visez une couverture de test élevée dans votre fichier de test unitaire
La couverture de code("code coverage" en anglais) est une mesure qui indique quel pourcentage de votre code source est couvert par les tests. Une couverture élevée est cruciale pour plusieurs raisons :
Elle garantit que la majorité de votre code est testée, réduisant ainsi les risques de bugs non détectés.
Avec une bonne couverture, vous pouvez refactoriser le code en toute confiance, sachant que les tests détecterons les régressions potentielles.
Elle donne une indication claire de la santé du projet.
Pour activer la couverture de code dans Xcode :
Activez la couverture de code (si celle-ci n’est pas déjà activée par défaut).
Sélectionnez le fichier de plan de test nommé “EPCollaboratif” dans le dossier approprié (je l’ai nommé “EPCollaboratifTests”).
Rédigez des tests unitaires
Maintenant que nous avons créé notre fichier de test unitaire, nous allons rédiger des tests pour vérifier les outputs du ViewModel. Il va falloir tester tous les cas, c’est-à-dire ceux qui fonctionnent mais aussi ceux qui ne devraient pas fonctionner. Pensez aussi aux scénarios qui doivent générer une erreur. On parle alors de test "happy path" pour un test d’un cas fonctionnel et de test "unhappy path" pour un test qui entraîne une erreur ou un comportement inattendu.
Voici une vidéo qui montre les principales étapes pour rédiger des tests unitaires.
Préparez votre fichier de test du ViewModel
Nous allons d’abord devoir intitialiser le fichier ViewModel avec des projets fictifs pour s'assurer que l'environnement de test est configuré avec les données nécessaires. Cette préparation est essentielle pour simuler un contexte réel où le ViewModel fonctionne avec des données spécifiques. Voici le code associé.
import XCTest
final class HomeScreenViewModelTests: XCTestCase {
var viewModel: HomeScreenViewModel!
var projects: [Project]!
override func setUp() {
super.setup()
projects = [
Project(id: 1, name: "Project Alpha", description: "Description Alpha", startDate: "2021-01-01", endDate: "2021-12-31", tasks: []),
Project(id: 2, name: "Project Beta", description: "Description Beta", startDate: "2021-01-01", endDate: "2021-12-31", tasks: [])
]
viewModel = HomeScreenViewModel(projects: projects)
}
}
Initiez-vous au concept Given/When/Then
Le modèle Given/When/Then est une façon structurée d'écrire des tests qui clarifient les étapes de préparation, d'action et de vérification :
Given : Mise en place des conditions initiales.
When : Exécution de l'action ou du comportement à tester.
Then : Vérification des résultats attendus.
Appliquez ce concept
Prenons l'exemple de la propriété titleText
dans le "HomeScreenViewModel". Voici comment vous pourriez écrire un test pour cette sortie :
Given : Initialisez l'état de départ du ViewModel.
When : Accédez à la propriété
titleText
.Then : Vérifiez que
titleText
est égal à la valeur attendue.
Voici le code associé.
var viewModel: HomeScreenViewModel!
var projects: [Project]!
override func setUp() {
super.setUp()
project = Project(id: 1, name: "Test Project", description: "Description", progress: 0.5, tasks: [])
viewModel = HomeScreenViewModel(projects: projects)
}
func testTitleText() {
// Given
let expectedTitle = "EPCollaboratif"
// When
let title = viewModel.titleText
// Then
XCTAssertEqual(title, expectedTitle, "Title text should be 'EPCollaboratif'")
}
Cet exemple est un cas très simple où la donnée exposée par l’output est statique et ne changera jamais. Regardons à présent le cas d’un output dynamique.
Given : Initialisez l'état de départ du ViewModel.
When : Accédez à la propriété
titleText
.Then : Vérifiez que
titleText
est égal à la valeur attendue.
var viewModel: HomeScreenViewModel!
var projects: [Project]!
// MARK: - Configuration et Teardown
override func setUp() {
super.setUp()
projects = [
Project(id: 1, name: "Projet Alpha", description: "Description Alpha", startDate: "2021-01-01", endDate: "2021-12-31", tasks: []),
Project(id: 2, name: "Projet Bêta", description: "Description Bêta", startDate: "2021-01-01", endDate: "2021-12-31", tasks: []),
]
viewModel = HomeScreenViewModel(projects: projects)
}
func testGivenValidIndex_WhenDeletingProject_ThenProjectIsDeleted() {
// Given
let deleteIndex = 0 // Index de "Projet Alpha"
// When
viewModel.deleteProject(at: deleteIndex)
// Then
XCTAssertEqual(viewModel.filteredProjects.count, 1, "Un projet devrait être supprimé.")
XCTAssertEqual(viewModel.filteredProjects.first?.name, "Projet Bêta", "Le projet restant devrait être 'Projet Bêta'.")
}
Jetez un oeil à l’intégralité du fichier ”HomeScreenViewModelTests”.
Exécutez et validez les tests
Vérifiez les résultats des tests
Une fois les tests exécutés, Xcode génère un rapport de test indiquant le statut de chaque test (succès ou échec). Voici comment interpréter les résultats :
Xcode affiche le rapport de test dans le panneau de navigation de gauche. Vous pouvez cliquer sur l'icône de la barre latérale pour ouvrir la section des tests.
Analysez les résultats :
Tests réussis : Les tests qui ont réussi apparaîtront avec une coche verte.
Tests échoués : Les tests qui ont échoué auront une croix rouge. Cliquez sur ces tests pour détailler l'erreur.
Les détails des tests échoués incluront des messages d'erreur spécifiques indiquant pourquoi le test a échoué. Utilisez ces informations pour diagnostiquer et corriger les problèmes dans votre ViewModel.
Le rapport d'exécution des tests pour le fichier ”HomeScreenViewModelTests” doit alors être comme ceci pour le moment.
Ici, on voit que neuf tests ont été exécutés. Huit ont échoué (indiqués par une croix rouge) et un seul a réussi (indiqué par une coche verte). Chaque test est nommé de manière descriptive, comme “testAddingDuplicateProject_DoesNotIncreaseProjectCount”, ce qui indique qu'il vérifie que l'ajout d'un projet en double n'augmente pas le nombre de projets. Vous trouverez aussi la durée d'exécution de chaque test, variant de quelques millisecondes à un peu plus de 0,05 secondes. Les échecs indiquent des problèmes potentiels à résoudre dans le code testé.
Aidez-vous l’Intelligence Artificielle pour générer des tests unitaires ! Vous pouvez utiliser des outils comme ChatGPT pour vous aider à générer des tests unitaires pour votre ViewModel. Cependant, il est important de noter les différences entre les versions de ChatGPT :
ChatGPT 3.5 : Il est capable de générer des tests simples et des scénarios courants, mais peut nécessiter des ajustements manuels pour des cas plus complexes.
ChatGPT 4 : Il offre une compréhension plus approfondie et peut générer des tests plus sophistiqués, avec une meilleure gestion des cas particuliers et des scénarios complexes.
À vous de jouer
Contexte
Vous avez appris l'importance des tests unitaires et la manière de configurer votre projet pour les inclure. Maintenant, il est temps de mettre en pratique ces connaissances en créant un fichier de test unitaire pour votre ViewModel.
Consignes
Initialisez le fichier de test unitaire.
Rédigez des tests pour les outputs.
Exécutez et validez les tests.
Livrable
Fichier de test “AddTaskViewModelTests" avec des tests pour les outputs définis.
Assurez-vous que les tests sont exécutés avec succès et que le projet compile sans erreur.
En résumé
Les tests unitaires sont cruciaux pour assurer la robustesse du ViewModel.
Les tests unitaires doivent être exécutés même si le ViewModel n'est pas encore fonctionnel pour vérifier que la configuration est correcte.
Pour maintenir une couverture de test élevée et assurer la fiabilité du code, il est important d’ajuster et d’améliorer les tests au fur et à mesure du développement.
Écrire des tests pour chaque output du ViewModel va vous permettre de couvrir tous les cas possibles.
La méthodologie Given/When/Then permet de structurer vos tests.
L’analyse des résultats et la lecture des rapports vont vous permettre d’identifier les différents problèmes.
Maintenant que vous avez une bonne compréhension de l'initialisation, de la rédaction et de l'exécution des tests unitaires, passons à la prochaine étape : implémenter la logique métier dans le ViewModel et vérifier que nos tests passent avec succès.