1. Avant de commencer
Dans les précédents ateliers de programmation, vous avez appris à utiliser des ViewModel
s pour gérer la logique métier, ainsi que LiveData
pour les UI réactives. Dans cet atelier de programmation, vous apprendrez à écrire des tests unitaires pour vérifier que votre code ViewModel
fonctionne correctement.
Conditions préalables
- Vous avez créé des répertoires de test dans Android Studio.
- Vous avez écrit des tests unitaires et des tests d'instrumentation dans Android Studio.
- Vous avez ajouté des dépendances Gradle à un projet Android.
Points abordés
- Écrire des tests unitaires pour les
ViewModel
s etLiveData
Ce dont vous avez besoin
- Un ordinateur sur lequel est installé Android Studio
- Code de solution de l'application Cupcake.
Télécharger le code de démarrage pour cet atelier de programmation
Dans cet atelier de programmation, vous ajouterez des tests d'instrumentation à l'application Cupcake à partir du code de solution précédent.
Pour obtenir le code de cet atelier de programmation et l'ouvrir dans Android Studio, procédez comme suit :
Obtenir le code
- Cliquez sur l'URL indiquée. La page GitHub du projet s'ouvre dans un navigateur.
- Vérifiez que le nom de la branche correspond au nom spécifié dans l'atelier de programmation. Par exemple, dans la capture d'écran suivante, le nom de la branche est main.
- Sur la page GitHub du projet, cliquez sur le bouton Code pour afficher une fenêtre pop-up.
- Dans la fenêtre pop-up, cliquez sur le bouton Download ZIP (Télécharger le fichier ZIP) pour enregistrer le projet sur votre ordinateur. Attendez la fin du téléchargement.
- Recherchez le fichier sur votre ordinateur (il se trouve probablement dans le dossier Téléchargements).
- Double-cliquez sur le fichier ZIP pour le décompresser. Un dossier contenant les fichiers du projet est alors créé.
Ouvrir le projet dans Android Studio
- Lancez Android Studio.
- Dans la fenêtre Welcome to Android Studio (Bienvenue dans Android Studio), cliquez sur Open (Ouvrir).
Remarque : Si Android Studio est déjà ouvert, sélectionnez l'option de menu File > Open (Fichier > Ouvrir).
- Dans l'explorateur de fichiers, accédez à l'emplacement du dossier du projet décompressé (il se trouve probablement dans le dossier Téléchargements).
- Double-cliquez sur le dossier de ce projet.
- Attendez qu'Android Studio ouvre le projet.
- Cliquez sur le bouton Run (Exécuter) pour créer et exécuter l'application. Assurez-vous qu'elle fonctionne correctement.
2. Présentation de l'application de démarrage
L'application Cupcake se compose d'un écran d'accueil qui affiche un écran de commande avec trois options pour les quantités de cupcakes. Si vous cliquez sur une option, vous accédez à un écran sur lequel vous pouvez sélectionner un parfum, ainsi que la date de collecte de la commande. Vous pouvez ensuite envoyer votre commande à une autre application. Vous pouvez aussi l'annuler à tout moment.
3. Créer un répertoire de test unitaire
Créez un répertoire de test unitaire pour l'application Cupcake, comme vous l'avez fait dans les précédents ateliers de programmation.
4. Créer une classe de test unitaire
Créez une classe appelée ViewModelTests.kt.
5. Ajouter les dépendances requises
Ajoutez les dépendances suivantes au projet :
testImplementation 'junit:junit:4.+'
testImplementation 'androidx.arch.core:core-testing:2.1.0'
Maintenant, synchronisez votre projet.
6. Écrire un test ViewModel
Prenons un exemple simple. La première chose que nous faisons lorsque nous interagissons avec l'application sur un appareil ou dans un émulateur consiste à sélectionner une quantité de cupcakes. Nous allons donc commencer par tester la méthode setQuantity()
dans OrderViewModel
et vérifier la valeur de l'objet LiveData
quantity
.
La variable quantity
, que nous allons tester, est une instance de LiveData
. Le test des objets LiveData
implique une étape supplémentaire, et c'est là que la dépendance que nous avons ajoutée entrera en jeu. Nous utiliserons LiveData
pour mettre à jour l'UI dès qu'une valeur change. Notre interface utilisateur s'exécute sur ce que nous appelons le "thread principal". Si vous n'êtes pas encore familier avec ce concept et avec la simultanéité, ne vous inquiétez pas. Nous approfondirons ce sujet plus dans d'autres ateliers de programmation. Pour le moment, dans le contexte d'une application Android, considérez le thread principal comme le thread UI. C'est sur ce thread que s'exécute le code qui présente l'interface utilisateur à un utilisateur. Sauf indication contraire, un test unitaire suppose que tout s'exécute sur le thread principal. Toutefois, comme les objets LiveData
ne peuvent pas accéder au thread principal, nous devons indiquer explicitement que les objets LiveData
ne doivent pas appeler le thread principal.
- Pour indiquer que les objets
LiveData
ne doivent pas appeler le thread principal, nous devrons fournir une règle de test spécifique chaque fois que nous testons un objetLiveData
.
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
- Nous pouvons maintenant créer une fonction appelée
quantity_twelve_cupcakes()
. Dans la méthode, créez une instance deOrderViewModel.
. - Dans ce test, vous allez vérifier que l'objet
quantity
d'OrderViewModel
est mis à jour lorsque la méthodesetQuantity
est appelée. Toutefois, avant d'appeler des méthodes ou d'utiliser des données dansOrderViewModel
, il est important de noter que, lorsque vous testez les valeurs d'un objetLiveData
, les objets doivent être observés pour que les modifications soient émises. Pour ce faire, vous pouvez utiliser la méthodeobserveForever
. Appelez la méthodeobserveForever
au niveau de l'objetquantity
. Cette méthode nécessite une expression lambda, mais peut être laissée vide. - Appelez ensuite la méthode
setQuantity()
en transmettant12
comme paramètre.
val viewModel = OrderViewModel()
viewModel.quantity.observeForever {}
viewModel.setQuantity(12)
- Nous pouvons déduire avec quasi-certitude que la valeur de l'objet
quantity
est12
. Notez que les objetsLiveData
ne correspondent pas à la valeur elle-même. Les valeurs se trouvent dans une propriété appeléevalue
. Effectuez l'assertion suivante :
assertEquals(12, viewModel.quantity.value)
Votre test devrait se présenter comme suit :
@Test
fun quantity_twelve_cupcakes() {
val viewModel = OrderViewModel()
viewModel.quantity.observeForever {}
viewModel.setQuantity(12)
assertEquals(12, viewModel.quantity.value)
}
Exécutez le test. Félicitations ! Vous venez d'écrire votre premier test unitaire LiveData
. C'est une compétence essentielle dans le développement Android moderne. Comme il ne teste pas vraiment la logique métier, nous allons écrire un test un peu plus complexe.
L'une des principales fonctions d'OrderViewModel
consiste à calculer le prix de notre commande. Ce calcul a lieu lorsque nous sélectionnons une quantité de cupcakes et une date de collecte. Étant donné que le calcul des prix s'effectue en mode privé, notre test ne peut pas appeler cette méthode directement. Seules les autres méthodes du modèle OrderViewModel
peuvent l'appeler. Ces méthodes étant publiques, nous les appellerons pour déclencher le calcul du prix, afin de vérifier que la valeur du prix correspond à nos attentes.
Bonnes pratiques
Le prix est mis à jour lorsque la quantité de cupcakes est sélectionnée, ainsi que la date de collecte. Bien que ces deux méthodes doivent être testées, il est généralement préférable de ne tester qu'une seule fonctionnalité à la fois. Par conséquent, nous créerons des méthodes distinctes pour chaque test : une fonction permettant de tester le prix lorsque la quantité est mise à jour, et une autre fonction pour tester le prix lorsque la date de collecte est mise à jour. Personne ne souhaite voir un test échouer à cause d'un autre test qui a échoué.
- Créez une méthode appelée
price_twelve_cupcakes()
et annotez-la en tant que test. - Dans la méthode, créez une instance d'
OrderViewModel
et appelez la méthodesetQuantity()
, en transmettant 12 en tant que paramètre.
val viewModel = OrderViewModel()
viewModel.setQuantity(12)
- En examinant l'élément
PRICE_PER_CUPCAKE
dansOrderViewModel
, nous constatons que les cupcakes coûtent 2 $ chacun. Nous pouvons également voir queresetOrder()
est appelé à chaque initialisation deViewModel
. Dans cette méthode, la date de collecte par défaut est la date du jour, etPRICE_FOR_SAME_DAY_PICKUP
correspond à 3 $. Dès lors, le calcul est le suivant : 12 * 2 + 3 = 27. La valeur de la variableprice
, après avoir sélectionné 12 cupcakes, devrait être de 27 $. Confirmons que la valeur attendue de 27 $ est égale à la valeur de l'objetprice LiveData
.
assertEquals("$27.00", viewModel.price.value)
Exécutez maintenant le test.
Il devrait échouer.
Le résultat du test indique que la valeur réelle est null
. Il existe une explication à cela. Si vous examinez la variable price
dans OrderViewModel
, vous verrez ce qui suit :
val price: LiveData<String> = Transformations.map(_price) {
// Format the price into the local currency and return this as LiveData<String>
NumberFormat.getCurrencyInstance().format(it)
}
C'est un exemple de la raison pour laquelle vous devez observer LiveData
lors des tests. La valeur de l'élément price
est définie à l'aide d'une Transformation
. Ce code convertit la valeur que nous attribuons à price
en un format de devise pour que nous n'ayons pas à le faire manuellement. Cependant, ce code a d'autres implications. Lors de la transformation d'un objet LiveData
, le code n'est pas appelé, sauf si c'est absolument nécessaire, ce qui permet d'économiser des ressources sur un appareil mobile. Le code n'est appelé que si nous observons l'objet à la recherche de modifications. Bien sûr, cela a lieu dans notre application, mais nous devons procéder de la même manière pour le test.
- Dans votre méthode de test, ajoutez la ligne suivante avant de définir la quantité :
viewModel.price.observeForever {}
Votre test devrait se présenter comme suit :
@Test
fun price_twelve_cupcakes() {
val viewModel = OrderViewModel()
viewModel.price.observeForever {}
viewModel.setQuantity(12)
assertEquals("$27.00", viewModel.price.value)
}
Si vous exécutez le test, il devrait réussir.
7. Code de solution
8. Félicitations
Voici les connaissances que vous avez acquises au cours de cet atelier de programmation :
- Vous avez appris à configurer un test
LiveData
. - Vous avez appris à tester
LiveData
lui-même. - Vous avez appris à tester
LiveData
, qui a été transformé. - Vous avez appris à observer
LiveData
dans un test unitaire.