1. Avant de commencer
Cet atelier de programmation vous présente les tests automatisés d'Android et explique en quoi ils permettent de développer des applications évolutives et robustes. Vous découvrirez également la différence entre la logique de l'interface utilisateur et la logique métier, et apprendrez à tester les deux. Enfin, vous apprendrez à écrire et à exécuter des tests automatisés dans Android Studio.
Conditions préalables
- Vous êtes capable d'écrire une application Android avec des fonctions et des composables.
Points abordés
- Ce que permettent de faire les tests automatisés sous Android
- En quoi les tests automatisés sont importants
- Ce qu'est un test en local et à quoi cela peut servir
- Ce qu'est un test d'instrumentation et à quoi cela peut servir
- Comment écrire des tests en local pour du code Android
- Comment écrire des tests d'instrumentation pour les applications Android
- Comment exécuter des tests automatisés
Objectifs de l'atelier
- Un test en local
- Un test d'instrumentation
Ce dont vous avez besoin
- La dernière version d'Android Studio
- Le code de solution de l'application Tip Time
2. Télécharger le code de démarrage
Pour télécharger le code :
Vous pouvez également cloner le dépôt GitHub du code :
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-tip-calculator.git $ cd basic-android-kotlin-compose-training-tip-calculator $ git checkout main
3. Tests automatisés
En ce qui concerne les logiciels, les tests constituent une méthode structurée qui permet de vérifier que tout fonctionne comme prévu. Les tests automatisés sont des lignes de code qui vérifient qu'un autre élément de code que vous avez écrit fonctionne correctement.
Les tests constituent une partie importante du processus de développement d'applications. En effectuant régulièrement des tests sur votre application, vous pouvez vérifier son adéquation, son comportement et son utilisation avant de la mettre à disposition de tous.
Les tests offrent également un moyen de vérifier en permanence le code existant à mesure que des modifications sont apportées.
Bien que des tests manuels soient presque toujours nécessaires, les tests sous Android peuvent souvent être automatisés. Tout au long de ce cours, vous vous concentrerez sur les tests automatisés pour tester le code de l'application et les exigences fonctionnelles de l'application elle-même. Dans cet atelier de programmation, vous allez découvrir les principes de base des tests sous Android. Dans les prochains ateliers, vous vous pencherez sur des pratiques plus avancées pour tester les applications Android.
À mesure que vous vous familiarisez avec le développement et les tests d'applications Android, habituez-vous à créer régulièrement des tests en parallèle à la création du code de votre application. En créant un test à chaque fois que vous ajoutez une fonctionnalité à votre application, vous réduisez la charge de travail à mesure que votre application prend de l'ampleur. Cela permet également de s'assurer que votre application fonctionne correctement sans passer trop de temps à la tester manuellement.
Les tests automatisés sont un élément essentiel de tout développement logiciel, et Android ne fait pas exception. C'est le moment idéal pour vous lancer !
En quoi les tests automatisés sont importants
Dans un premier temps, vous pourriez avoir l'impression que vous n'avez pas vraiment besoin de tester votre application. Détrompez-vous : il s'agit d'une étape indispensable, quelle que soit la taille ou la complexité de votre projet.
Pour développer votre codebase, vous devez tester les fonctionnalités existantes tout en ajoutant des éléments, ce qui n'est possible que si vous disposez déjà de tests. À mesure que votre application prend de l'ampleur, les tests manuels demandent beaucoup plus d'efforts que les tests automatisés. De plus, lorsque vous commencez à travailler sur des applications en production, les tests deviennent d'autant plus incontournables, en particulier lorsque votre base d'utilisateurs est étendue. Par exemple, vous devez prendre en compte de nombreux types d'appareils, équipés de diverses versions d'Android.
Arrivé à un certain stade, vous atteignez un niveau où les tests automatisés représentent la majorité des scénarios d'utilisation bien plus rapidement que les tests manuels. Lorsque vous exécutez des tests avant de publier le nouveau code, vous pouvez modifier le code existant afin d'éviter de publier une application présentant des comportements inattendus.
N'oubliez pas que les tests automatisés sont exécutés à l'aide d'un logiciel, par opposition aux tests manuels effectués par une personne qui interagit directement avec un appareil. Les tests automatisés et manuels jouent un rôle essentiel pour que les utilisateurs bénéficient d'une expérience agréable. Toutefois, les tests automatisés peuvent être plus précis et optimiser la productivité de votre équipe, car ils s'exécutent de façon autonome. De plus, leur exécution est beaucoup plus rapide que les tests manuels.
Types de tests automatisés
Tests en local
Les tests en local testent directement un court extrait de code pour vérifier qu'il fonctionne correctement. Vous pouvez ainsi tester des fonctions, des classes et des propriétés. Les tests locaux sont exécutés sur votre poste de travail, ce qui signifie qu'ils s'exécutent dans un environnement de développement sans nécessiter d'appareil ni d'émulateur. Pour le dire plus simplement, les tests en local sont exécutés sur votre ordinateur. De plus, les frais généraux associés sont très faibles en termes de ressources informatiques, ce qui leur permet de fonctionner rapidement, même avec des ressources limitées. Android Studio est conçu pour exécuter automatiquement des tests en local.
Tests d'instrumentation
En ce qui concerne le développement Android, un test d'instrumentation est un test de l'interface utilisateur. Les tests d'instrumentation vous permettent de tester des parties d'une application qui dépendent de l'API Android, ainsi que de ses services et API de plate-forme.
Contrairement aux tests en local, les tests d'interface utilisateur (UI) lancent une application ou une partie d'une application, simulent les interactions des utilisateurs et vérifient que la réaction est correcte. Tout au long de ce cours, les tests d'UI sont exécutés sur un appareil physique ou un émulateur.
Lorsque vous exécutez un test d'instrumentation sous Android, le code de test est en réalité intégré à son propre Android Application Package (APK), comme une application Android standard. Un APK est un fichier compressé contenant l'ensemble du code et des fichiers nécessaires à l'exécution de l'application sur un appareil ou un émulateur. L'APK de test est installé sur l'appareil ou l'émulateur avec l'APK d'application standard. L'APK de test effectue ensuite ses tests par rapport à l'APK de l'application.
4. Écrire un test en local
Préparer le code de l'application
Les tests en local testent directement des méthodes à partir du code de l'application. Les méthodes à tester doivent donc être disponibles pour les classes et les méthodes de test. Le test en local de l'extrait de code suivant vérifie que la méthode calculateTip()
fonctionne correctement, mais calculateTip()
est actuellement privée (private
) et n'est donc pas accessible à partir du test. Supprimez la désignation private
et passez-la en internal
(interne) :
MainActivity.kt
internal fun calculateTip(amount: Double, tipPercent: Double = 15.0, roundUp: Boolean): String {
var tip = tipPercent / 100 * amount
if (roundUp) {
tip = kotlin.math.ceil(tip)
}
return NumberFormat.getCurrencyInstance().format(tip)
}
- Dans le fichier
MainActivity.kt
, sur la ligne située avant la méthodecalculateTip()
, ajoutez l'annotation@VisibleForTesting
:
@VisibleForTesting
internal fun calculateTip(amount: Double, tipPercent: Double = 15.0, roundUp: Boolean): String {
var tip = tipPercent / 100 * amount
if (roundUp) {
tip = kotlin.math.ceil(tip)
}
return NumberFormat.getCurrencyInstance().format(tip)
}
La méthode est rendue publique, mais elle indique qu'elle n'est publique qu'à des fins de test.
Créer le répertoire de tests
Dans les projets Android, le répertoire test
est l'endroit où les tests locaux sont écrits.
Créez le répertoire de tests :
- Dans l'onglet Project (Projet), définissez la vue sur "Project" (Projet).
- Effectuez un clic droit sur le répertoire src.
- Sélectionnez New > Directory (Nouveau > Répertoire).
- Dans la fenêtre New Directory (Nouveau répertoire), sélectionnez test/java.
- Appuyez sur la touche Retour ou Entrée du clavier. Le répertoire test s'affiche désormais dans l'onglet Project (Projet).
Le répertoire test nécessite une structure de packages identique à celle du répertoire main
, qui contient le code de votre appli. En d'autres termes, comme votre code d'application est écrit dans le package main > java > com > example > tiptime, vos tests locaux sont écrits dans test > java > com > example > tiptime.
Créez cette structure de packages dans le répertoire de tests :
- Effectuez un clic droit sur le répertoire test/java, puis sélectionnez New > Package (Nouveau > Package).
- Dans la fenêtre New Package (Nouveau package), saisissez
com.example.tiptime
.
Créer la classe de test
Maintenant que le package de test est prêt, il est temps d'écrire des tests. Commencez par créer la classe de test.
- Dans l'onglet Project (Projet), cliquez sur app > src > test, puis sur la flèche de développement à côté du répertoire
test
. - Effectuez un clic droit sur le répertoire
com.example.tiptime
, puis sélectionnez New > Kotlin Class/File (Nouveau > Classe/Fichier Kotlin).
- Saisissez
TipCalculatorTests
comme nom de classe.
Écrire le test
Comme indiqué précédemment, les tests en local sont utilisés pour tester de courts extraits de code dans l'application. La fonction principale de l'application Tip Time est de calculer des pourboires : le test en local doit donc s'assurer que la logique de calcul fonctionne correctement.
Pour ce faire, vous devez appeler directement la fonction calculateTip()
, comme vous l'avez fait dans le code de l'application. Ensuite, vérifiez que la valeur renvoyée correspond au résultat attendu par rapport aux valeurs que vous avez transmises à la fonction.
Voici quelques points à garder à l'esprit concernant l'écriture de tests automatisés. La liste de concepts suivante s'applique aux tests en local, mais aussi aux tests d'instrumentation. À première vue, ils peuvent sembler abstraits, mais d'ici la fin de cet atelier de programmation, vous aurez eu l'occasion de vous familiariser avec ces concepts.
- Rédigez vos tests automatisés sous la forme de méthodes.
- Annotez la méthode avec
@Test
. De cette façon, le compilateur sait qu'il s'agit d'une méthode de test et l'exécute en conséquence.
- Assurez-vous que le nom décrit clairement l'objet du test et le résultat attendu.
- Les méthodes de test n'utilisent pas la même logique que les méthodes d'application standards. Elles ne se préoccupent pas de la mise en œuvre. Elles se contentent de vérifier le résultat pour une entrée donnée. Autrement dit, les méthodes de test n'exécutent qu'un ensemble d'instructions pour vérifier que l'interface utilisateur ou la logique d'une application fonctionne correctement. À ce stade, il n'est pas nécessaire de comprendre ce que cela signifie, car vous verrez le fonctionnement plus tard. Toutefois, n'oubliez pas que le code de test peut être très différent du code d'application dont vous avez l'habitude.
- Les tests se terminent généralement par une assertion qui permet de vérifier qu'une condition donnée est remplie. Les assertions se présentent sous la forme d'un appel de méthode dont le nom contient assert. Par exemple, l'assertion
assertTrue()
est communément utilisée dans les tests Android. Les instructions d'assertion sont utilisées dans la plupart des tests, mais ce n'est que rarement le cas dans du code d'application.
Écrivez le test :
- Créez une méthode pour tester le calcul d'un pourboire de 20 % pour un montant de 10 $. Le résultat attendu de ce calcul est 2 $.
import org.junit.Test
class TipCalculatorTests {
@Test
fun calculateTip_20PercentNoRoundup() {
}
}
N'oubliez pas que la méthode calculateTip()
du fichier MainActivity.kt
dans le code de l'application nécessite trois paramètres : le montant de la facture, le pourcentage du pourboire et un indicateur permettant d'arrondir ou non le résultat.
fun calculateTip(amount: Double, tipPercent: Double, roundUp: Boolean)
Lorsque cette méthode doit être appelée à partir du test, ces paramètres doivent être transmis de la même façon que dans le code de l'application.
- Dans la méthode
calculateTip_20PercentNoRoundup()
, créez deux variables constantes : une variableamount
définie sur la valeur10.00
et une variabletipPercent
définie sur la valeur20.00
.
val amount = 10.00
val tipPercent = 20.00
- Dans le fichier
MainActivity.kt
du code de l'application, observez le code suivant. Le montant du pourboire est mis en forme en fonction des paramètres régionaux de l'appareil.
MainActivity.kt
...
NumberFormat.getCurrencyInstance().format(tip)
...
La même mise en forme doit être utilisée lors de la vérification du montant du pourboire attendu dans le test.
- Créez une variable
expectedTip
définie surNumberFormat.getCurrencyInstance().format(2)
.
La variable expectedTip
est ensuite comparée au résultat de la méthode calculateTip()
. C'est de cette façon que le test garantit le bon fonctionnement de la méthode. À l'étape précédente, vous avez défini la variable amount
sur une valeur de 10.00
et la variable tipPercent
sur une valeur de 20.00
. Vingt pour cent de 10 $ font 2 $, d'où la variable expectedTip
définie sur une devise mise en forme avec une valeur de 2
. Gardez à l'esprit que la méthode calculateTip()
renvoie une valeur String
mise en forme.
- Appelez la méthode
calculateTip()
avec les variablesamount
ettipPercent
, puis transmettez un argumentfalse
pour l'arrondi.
Dans le cas présent, vous n'avez pas besoin de vous soucier d'arrondir, car le résultat attendu n'est pas concerné par les arrondis.
- Stockez le résultat de l'appel de méthode dans une variable
actualTip
constante.
Jusqu'à présent, l'écriture de ce test ne diffère pas beaucoup de celle d'une méthode standard dans le code d'une application. Toutefois, maintenant que vous disposez de la valeur renvoyée par la méthode que vous souhaitez tester, vous devez déterminer si cette valeur est correcte en utilisant une assertion.
En règle générale, les assertions sont l'objectif final d'un test automatisé, ce pour quoi elles ne sont pas communément utilisées dans du code d'application réel. Ici, vous devez vous assurer que la variable actualTip
correspond à la variable expectedTip
. Pour ce faire, vous pouvez utiliser la méthode assertEquals()
de la bibliothèque JUnit
.
La méthode assertEquals()
prend deux paramètres en entrée : une valeur attendue et une valeur réelle. Si ces valeurs sont égales, l'assertion et le test sont concluants. Dans le cas contraire, l'assertion et le test échouent.
- Appelez la méthode
assertEquals()
, puis transmettez les variablesexpectedTip
etactualTip
en tant que paramètres :
import org.junit.Assert.assertEquals
import org.junit.Test
import java.text.NumberFormat
class TipCalculatorTests {
@Test
fun calculateTip_20PercentNoRoundup() {
val amount = 10.00
val tipPercent = 20.00
val expectedTip = NumberFormat.getCurrencyInstance().format(2)
val actualTip = calculateTip(amount = amount, tipPercent = tipPercent, false)
assertEquals(expectedTip, actualTip)
}
}
Exécuter le test
Vous pouvez maintenant exécuter votre test !
Vous avez peut-être remarqué que des flèches apparaissent à côté du numéro de ligne du nom de classe et de la fonction de test. Vous pouvez cliquer sur ces flèches pour lancer le test. Lorsque vous cliquez sur la flèche située à côté d'une méthode, vous n'exécutez que la méthode de test en question. Si une classe comporte plusieurs méthodes de test, vous pouvez cliquer sur la flèche située à côté de la classe pour lancer toutes les méthodes de test qu'elle contient.
Exécutez le test :
- Cliquez sur les flèches à côté de la déclaration de la classe, puis sur Run 'TipCalculatorTests' (Exécuter 'TipCalculatorTests').
Le résultat suivant doit s'afficher :
- La sortie s'affiche en bas du volet Run (Exécuter).
5. Écrire un test d'instrumentation
Créer le répertoire d'instrumentation
Le répertoire d'instrumentation est créé de la même manière que le répertoire de tests local.
- Effectuez un clic droit sur le répertoire src, puis sélectionnez New > Directory (Nouveau > Répertoire).
- Dans la fenêtre New Directory (Nouveau répertoire), sélectionnez androidTest/java.
- Appuyez sur la touche Retour ou Entrée du clavier. Le répertoire androidTest s'affiche désormais dans l'onglet Project (Projet).
Tout comme les répertoires main
et test
ont la même structure de packages, le répertoire androidTest
doit contenir cette même structure.
- Effectuez un clic droit sur le dossier androidTest/java, puis sélectionnez New > Package (Nouveau > Package).
- Dans la fenêtre New Package (Nouveau package), saisissez
com.example.tiptime
. - Appuyez sur la touche Retour ou Entrée du clavier. La structure complète des packages du répertoire
androidTest
est maintenant visible dans l'onglet Project (Projet).
Créer la classe de test
Dans les projets Android, le répertoire de test d'instrumentation est androidTest
.
Pour créer un test d'instrumentation, vous devez répéter le processus que vous avez utilisé pour créer un test local, mais cette fois-ci dans le répertoire androidTest
.
Créez la classe de test :
- Dans le volet du projet, accédez au répertoire
androidTest
. - Cliquez sur les flèches de développement à côté de chaque répertoire jusqu'à trouver
tiptime
.
- Effectuez un clic droit sur le répertoire
tiptime
, puis sélectionnez New > Kotlin Class/File (Nouveau > Classe/Fichier Kotlin). - Saisissez
TipUITests
comme nom de classe.
Écrire le test
Le code d'un test d'instrumentation est assez différent du code d'un test en local.
Les tests d'instrumentation testent une instance réelle de l'application et de son interface utilisateur. Par conséquent, le contenu de l'UI doit être défini de la même manière que vous l'avez fait avec la méthode onCreate()
du fichier MainActivity.kt
lorsque vous avez écrit le code de l'application Tip Time. Il s'agit d'un prérequis à l'écriture de tous les tests d'instrumentation pour les applications créées avec Compose.
Dans le cas des tests de l'application Tip Time, vous allez rédiger des instructions pour interagir avec les composants de l'UI, de sorte que le processus de calcul des pourboires soit testé via l'interface utilisateur. Le concept d'un test d'instrumentation peut sembler abstrait au début, mais ne vous inquiétez pas ! Nous allons détailler ce processus au cours des étapes suivantes.
Écrivez le test :
- Créez une variable
composeTestRule
définie sur le résultat de la méthodecreateComposeRule()
, puis annotez-la avecRule
:
import androidx.compose.ui.test.junit4.createComposeRule
import org.junit.Rule
class TipUITests {
@get:Rule
val composeTestRule = createComposeRule()
}
- Créez une méthode
calculate_20_percent_tip()
et annotez-la avec@Test
:
import org.junit.Test
@Test
fun calculate_20_percent_tip() {
}
Le compilateur sait que les méthodes annotées avec @Test
dans le répertoire androidTest
font référence à des tests d'instrumentation et que les méthodes annotées avec @Test
dans le répertoire test
font référence à des tests en local.
- Dans le corps de la fonction, appelez
composeTestRule.setContent()
. Cela définit le contenu de l'interface utilisateur decomposeTestRule
. - Dans le corps du lambda de la fonction, appelez
TipTimeTheme()
avec un corps de lambda qui appelleTipTimeLayout()
.
import com.example.tiptime.ui.theme.TipTimeTheme
@Test
fun calculate_20_percent_tip() {
composeTestRule.setContent {
TipTimeTheme {
TipTimeLayout()
}
}
}
Lorsque vous avez terminé, le code doit ressembler à celui écrit pour définir le contenu de la méthode onCreate()
dans le fichier MainActivity.kt
. Maintenant que le contenu de l'UI est configuré, vous pouvez rédiger des instructions pour interagir avec les composants de l'interface de l'application. Dans cette application, vous devez vérifier qu'elle affiche la valeur correcte du pourboire en fonction du montant de la facture et des pourcentages de pourboire saisis.
- Les composants d'interface utilisateur sont accessibles en tant que nœuds via
composeTestRule
. Pour ce faire, une technique communément utilisée consiste à accéder à un nœud contenant un texte particulier à l'aide de la méthodeonNodeWithText()
. Utilisez la méthodeonNodeWithText()
afin d'accéder au composableTextField
pour le montant de la facture :
import androidx.compose.ui.test.onNodeWithText
@Test
fun calculate_20_percent_tip() {
composeTestRule.setContent {
TipTimeTheme {
TipTimeLayout()
}
}
composeTestRule.onNodeWithText("Bill Amount")
}
Vous pouvez ensuite appeler la méthode performTextInput()
et transmettre le texte que vous souhaitez saisir pour remplir le composable TextField
.
- Dans le champ
TextField
, indiquez le montant de la facture avec une valeur10
:
import androidx.compose.ui.test.performTextInput
@Test
fun calculate_20_percent_tip() {
composeTestRule.setContent {
TipTimeTheme {
TipTimeLayout()
}
}
composeTestRule.onNodeWithText("Bill Amount")
.performTextInput("10")
}
- Utilisez la même approche pour renseigner le champ
OutlinedTextField
avec le pourcentage de pourboire, en l'occurrence une valeur de20
:
@Test
fun calculate_20_percent_tip() {
composeTestRule.setContent {
TipTimeTheme {
TipTimeLayout()
}
}
composeTestRule.onNodeWithText("Bill Amount")
.performTextInput("10")
composeTestRule.onNodeWithText("Tip Percentage").performTextInput("20")
}
Une fois que tous les composables TextField
ont été renseignés, le pourboire s'affiche dans un composable Text
en bas de l'écran dans l'application.
Maintenant que vous avez demandé au test d'insérer ces composables TextField
, vous devez vous assurer que le composable Text
affiche le bon pourboire à l'aide d'une assertion.
Dans les tests d'instrumentation avec Compose, les assertions peuvent être appelées directement sur les composants d'UI. De nombreuses assertions sont disponibles, mais dans le cas présent, vous allez utiliser la méthode assertExists()
. Le composable Text
, qui affiche le montant du pourboire, doit s'afficher ainsi : Tip Amount: $2.00
.
- Créez une assertion pour vérifier qu'un nœud contenant ce texte existe :
import java.text.NumberFormat
@Test
fun calculate_20_percent_tip() {
composeTestRule.setContent {
TipTimeTheme {
Surface (modifier = Modifier.fillMaxSize()){
TipTimeLayout()
}
}
}
composeTestRule.onNodeWithText("Bill Amount")
.performTextInput("10")
composeTestRule.onNodeWithText("Tip Percentage").performTextInput("20")
val expectedTip = NumberFormat.getCurrencyInstance().format(2)
composeTestRule.onNodeWithText("Tip Amount: $expectedTip").assertExists(
"No node with this text was found."
)
}
Exécuter le test
Le processus d'exécution d'un test d'instrumentation est identique à celui d'un test en local. Vous pouvez cliquer sur les flèches dans la marge, en face de chaque déclaration, pour exécuter un test individuel ou l'ensemble de la classe de test.
- Cliquez sur les flèches en face de la déclaration de classe. Vous pouvez voir les tests s'exécuter sur votre appareil ou émulateur. Une fois le test terminé, vous devriez obtenir la sortie suivante :
6. Télécharger le code de solution
Vous pouvez également cloner le dépôt GitHub du code :
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-tip-calculator.git $ cd basic-android-kotlin-compose-training-tip-calculator $ git checkout test_solution
7. Conclusion
Félicitations ! Vous avez rédigé vos premiers tests automatisés pour Android. Les tests jouent un rôle essentiel dans le contrôle qualité des logiciels. À mesure que vous développez des applications Android, veillez à rédiger des tests en même temps que les fonctionnalités en elles-mêmes pour vous assurer qu'elles fonctionnent correctement tout au long du processus de développement.
Résumé
- Définition des tests automatisés
- En quoi les tests automatisés sont importants
- Différence entre les tests en local et les tests d'instrumentation
- Bonnes pratiques essentielles pour rédiger des tests automatisés
- Où trouver et placer des classes de test en local et d'instrumentation dans un projet Android
- Comment créer une méthode de test
- Comment créer des classes de test en local et d'instrumentation
- Comment effectuer des assertions dans les tests en local et d'instrumentation
- Comment utiliser des règles de test
- Comment utiliser
ComposeTestRule
pour lancer l'application avec un test - Comment interagir avec les composables dans un test d'instrumentation
- Comment exécuter des tests