Maintenant que votre base de données est fonctionnelle et que Room est en place, l’étape suivante est de s’assurer de la qualité du code en commençant par l’écriture de tests.
Découvrez les types de tests
L’écriture de tests est une partie très importante du développement logiciel et ce quelle que soit la nature du logiciel développé (site web, client lourd, application mobile, etc.) et le langage de programmation utilisé (Kotlin, Java, Swift, PHP, C#, Go, Typescript, etc.). Écrire des tests c’est valider le comportement fonctionnel et la stabilité technique du logiciel à travers l’exécution de scénarios prédéfinis.
S’il est possible de tester manuellement un logiciel ce n’est généralement pas la voix recommandée. En effet, tester manuellement c’est laisser place aux erreurs humaines et possiblement laisser passer des régressions. C’est pourquoi on privilégie les tests automatisés effectués à votre place. Ces tests présentent les avantages d’être plus rapide à exécuter et sont surtout plus reproductibles car “scriptés”. Ils suivent un scénario que vous avez écrit.
Dans le cadre des applications Android, quand on parle de tests automatisés, on les dispose généralement sur ce qu’on appelle la pyramide des tests.
Les tests unitaires
Les tests unitaires sont le premier étage de la pyramide. L’objectif principal de ces tests est de pouvoir tester de petites portions de code, qui ne présentent pas de dépendances au framework Android, comme une méthode ou une classe, afin de garantir qu’elles fonctionnent comme prévu.
Les tests unitaires représentent environ 70% des tests d’une application mobile. Ils sont considérés comme des tests locaux, c’est-à-dire qu’ils s'exécutent directement sur l’ordinateur. Puisqu’ils ne s’exécutent pas sur un téléphone ou un émulateur Android, ils n’ont pas connaissance du framework Android. Dans le cas contraire, ces dépendances peuvent être mockées (ou simulées) à l’aide d’outils dédiés comme Mockk ou mockito.
Les tests d'intégration
Les tests d’intégration sont le deuxième étage de la pyramide. L’objectif principal des tests d’intégration est de pouvoir tester les modules de l’application présentant une dépendance forte au framework Android comme les activités, les fragments, les services ou encore les bases de données. Ces tests permettent également de tester les interactions entre ces modules comme entre les DAOs et une base de données.
Les tests d’intégration représentent environ 20% des tests d’une application mobile. Puisqu’ils permettent de tester des modules présentant une dépendance au framework Android, ils doivent s’exécuter sur un appareil Android physique ou émulé. On parle alors de tests d’instrumentation.
Les tests d’interface graphique ou tests fonctionnels
Finalement, le troisième et dernier étage de la pyramide des tests est celui des tests d’interface graphique. L’objectif principal des tests d’interface graphique est de garantir que l’interface graphique de l’application mobile fonctionne comme prévu. Ils se concentrent donc sur l'interaction entre l'utilisateur et l'application, en vérifiant notamment la réactivité des composants graphiques (boutons, liste, zone de saisie, etc.), la cohérence visuelle et la gestion des erreurs.
Les tests d’interface graphique représentent environ 10% des tests d’une application mobile. Pour tester l’interface graphique, ces tests doivent lancer l’application. Ils doivent s’exécuter sur un appareil Android physique ou émulé. Il s’agit donc également de tests d’instrumentation.
D’autres types de tests
Le sujet des tests dans le développement logiciel et tout particulièrement le développement d’une application Android peut faire l’objet d’un cours à part entière. En effet, les tests présentés dans la pyramide ne sont pas les seuls tests qu’il est possible d’écrire. Pour approfondir le sujet, découvrez le cours “Testez votre code Java pour réaliser des applications de qualité“.
Testez une base de données Room
Dans le cadre des tests de la base de données de l’application PETiSoin, vous allez mettre en place des tests d’intégration qui s'exécuteront sur un appareil Android physique ou émulé.
Afin de tester efficacement la base de données de l’application PETiSoin, les tests que vous écrirez couvriront les DAO.
Créez votre première classe de tests
Avant d’écrire les tests, il est nécessaire de référencer, au sein du catalogue Gradle du projet Android, l’ensemble des dépendances qui permettront de les écrire.
1. Pour ce faire, rendez-vous dans le dossier Gradle du projet.
2. Ouvrez dans Android Studio le fichier "libs.versions.toml". Assurez-vous que les bibliothèques JUnit sont bien présentes dans le fichier.
[versions]
junit = "4.13.2"
junitVersion = "1.1.5"
[libraries]
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
3. Vérifiez que ces bibliothèques sont bien appliquées en dépendance dans le fichier build.gradle.kts du module app.
dependencies {
//…
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
}
Étape 1 : Créez la classe de test
Maintenant que le projet PETiSoin est correctement configuré, les premiers tests peuvent être écrits via les tests de l’interfaceAnimalDao
dont le code est le suivant.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
Puisqu’il s’agit d’un test d'instrumentation, il est nécessaire de préciser le test runner à utiliser pour exécuter le test. Dans le cas présent, vous pouvez utiliser le test runnerAndroidJUnit4
qui est généralement celui utilisé par défaut.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
Étape 2 : Initialisez la base de données pour le test
La deuxième étape consiste à écrire l’étape d’initialisation du test, c’est-à-dire l’étape qui sera exécutée avant chacun des tests contenus dans la classeAnimalDaoTest
.
L’étape d’initialisation consiste simplement à créer une nouvelle instance de la base de données. Pour faciliter la manipulation de la base de données, nous allons utiliser plusieurs options.
La première option concerne le stockage des données. Dans le cadre des tests, la bonne pratique consiste à stocker l’ensemble des données dans la RAM. Vous allez donc créer une base de données in memory pour que les données qui seront manipulées lors du test ne lui survivent pas. Cette option permet donc d’assurer le côté unitaire des différents tests que vous allez écrire en supprimant les adhérences entre les tests, c’est-à-dire en éliminant tout risque qu’un test puisse avoir des conséquences sur un autre test.
La seconde option concerne la gestion du threading. La gestion des threads dans une application n’est pas une chose évidente car elle implique souvent du code qui s’exécute de manière asynchrone. Ça l’est encore moins lorsque l’on écrit des tests. Pour faciliter l’écriture des tests, vous pouvez donc préciser à Room de désactiver la vérification des requêtes sur le thread principal.
Pour mettre en place cette étape d’initialisation:
Ajoutez une méthode
createDb()
et un attributdatabase
à la classeAnimalDaoTest
.Annotez la méthode
createDb()
avec@Before
pour préciser que cette méthode doit être appelée avant l’exécution de chacun des tests.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
Étape 3 : Fermez la base de données après le test
Avant d'écrire votre premier test, une dernière étape est nécessaire : fermer la base de données après l’exécution d’un test.
Cela garantit que toutes les ressources SQlite ouvertes lors du test sont correctement libérées. On évite ainsi des fuites de mémoire et des potentiels effets de bord lors de l’exécution du test suivant.
Pour mettre en place cette étape de fermeture :
Ajoutez une méthode
closeDb()
à la classeAnimalDaoTest
dans laquelle vous appelez la méthodeclose()
sur l’attributdatabase
.Annotez la méthode
closeDb()
avec@After
pour préciser que cette méthode doit être appelée après l’exécution de chacun des tests.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
Voici une vidéo qui récapitule les principales étapes pour préparer vos tests.
À vous de jouer
Contexte
Il est temps de préparer les tests pour vérifier le travail que vous avez effectué jusqu'à maintenant sur l’application PETiSoin et plus particulièrement sa rubrique “Santé”.
Consignes
Dans le projet, disponible sur GitHub (Java ou Kotlin), créez la classeVaccineDaoTest
qui permettra plus tard de tester le DAOVaccineDao
. Cette classe doit créer une base de données mémoire avant chaque test et doit être fermée après chaque test.
Livrables
Vous pouvez dupliquer le projet GitHub pour modifier le code source du projet et fournir un projet dont l’ensemble des tests passent.
En résumé
Pour tester les DAOs de la base de données, il convient d’écrire des tests d’instrumentation qui s’exécutent sur appareil Android physique ou émulé.
Pour manipuler la base de données dans les tests, on privilégie une base de données in memory sur laquelle la manipulation sur le thread principal est permise.
À la fin de chaque test, il est important de fermer la base de données.
Vous êtes enfin prêt à rédiger vos tests pour vérifier que tous les DAO de votre application Android fonctionnent correctement.