1. Livres & vidéos
  2. Kotlin
  3. Assurer la qualité du code
Extrait - Kotlin Du code au Play Store : le guide complet pour développeurs Android
Extraits du livre
Kotlin Du code au Play Store : le guide complet pour développeurs Android Revenir à la page d'achat du livre

Assurer la qualité du code

Utiliser les outils de débogage dans Android Studio

Le débogage est une compétence essentielle pour développer des applications Android fiables. Au-delà de la simple correction d’erreurs, c’est une méthode pour comprendre le comportement du code et identifier l’origine des problèmes. Maîtriser les outils de débogage d’Android Studio aide à diagnostiquer les bugs plus rapidement.

Android Studio propose une suite d’outils de débogage qui simplifient l’investigation des problèmes. Ces outils permettent d’observer le comportement du code en temps réel, d’inspecter les valeurs des variables et de suivre le flux d’exécution pas à pas. Apprendre à les utiliser améliore l’efficacité au quotidien.

1. Points d’arrêt et débogage pas à pas

Les points d’arrêt (breakpoints) sont l’outil de base du débogage moderne. Ils permettent de suspendre l’exécution de l’application à des endroits précis pour examiner l’état du programme.

La création d’un point d’arrêt s’effectue en cliquant dans la marge gauche de l’éditeur, à côté de la ligne où vous souhaitez arrêter l’exécution. Une fois le point d’arrêt placé, lancez votre application en mode debug en cliquant sur l’icône verte dans la barre d’outils.

class UserViewModel : ViewModel() { 
fun loadUser(userId: Int) { 
// Placer un breakpoint ici pour examiner userId 
val user = userRepository.getUser(userId) 
    // Autre breakpoint pour vérifier le résultat ...

Écrire des tests unitaires avec JUnit

Les tests unitaires sont à la base d’une stratégie de qualité logicielle, permettant de valider le comportement de votre code de manière automatisée et répétable. Ils remplacent la vérification manuelle par un processus automatique qui détecte les régressions dès leur introduction.

JUnit (framework standard de tests unitaires sur la JVM) est le framework de test standard pour les projets Kotlin et Android. Son API est simple à prendre en main, mais elle reste assez flexible pour traiter des scénarios complexes sans nuire à la lisibilité du code de test.

1. Configuration et premiers tests

La mise en place de JUnit dans un projet Android est automatique : tout nouveau projet créé avec Android Studio dispose déjà des dépendances nécessaires dans le fichier build.gradle. Vous pouvez écrire vos premiers tests dès la création du projet.

dependencies { 
  testImplementation 'junit:junit:4.13.2'  
  testImplementation 'org.mockito:mockito-core:4.6.1' 
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-
test:1.6.4' 
} 

La structure d’un test JUnit suit un schéma simple et prévisible, facile à comprendre et à maintenir. Chaque test vérifie un comportement précis du code à l’aide d’assertions qui comparent le résultat obtenu au résultat attendu.

class CalculatorTest { 
private lateinit var calculator: Calculator 
 
@Before 
fun setup() { 
    calculator = Calculator() 
} 
 
@Test 
fun addition_withPositiveNumbers_returnsCorrectSum() { 
    // Arrange (Préparer) 
    val firstNumber = 5 
    val secondNumber = 3 
    
    // Act (Agir) 
    val result = calculator.add(firstNumber, secondNumber) ...

Valider l’interface utilisateur avec Espresso

Espresso (framework de tests d’interface Android) est l’outil de test d’interface utilisateur historique d’Android. Il valide automatiquement le comportement des écrans et les interactions utilisateur. Ces tests complètent les tests unitaires en vérifiant que l’intégration entre les composants fonctionne dans un environnement réel. Espresso devient utile dès que les interfaces se complexifient.

Les tests Espresso simulent les actions d’un utilisateur réel : clics, saisies de texte, navigations et vérifications visuelles. Cette simulation automatisée détecte les problèmes d’interface invisibles aux tests unitaires, comme les erreurs de mise en page ou de navigation.

1. Configuration et premier test d’interface

La configuration d’Espresso nécessite l’ajout de dépendances spécifiques dans le fichier build.gradle. Ces dépendances activent les fonctionnalités de test d’interface et l’intégration avec les composants Android.

dependencies { 
androidTestImplementation 'androidx.test.ext:junit:1.1.5' 
androidTestImplementation 'androidx.test.espresso:espresso-
core:3.5.1' androidTestImplementation 
'androidx.test:runner:1.5.2' androidTestImplementation 
'androidx.test:rules:1.5.0' 
} 

La structure d’un test Espresso suit le schéma Find-Perform-Check (rechercher, agir, vérifier) : trouver un élément d’interface, exécuter une action dessus, puis vérifier le résultat....

Bonnes pratiques pour tests et maintenance

Mettre en place une stratégie de test efficace ne se limite pas à l’écriture de tests individuels : elle suppose une approche systématique pour maintenir la qualité du code dans la durée. Elle doit équilibrer couverture de code, maintenabilité des tests et productivité. Adopter de bonnes pratiques dès le début du projet évite d’accumuler de la dette technique.

La maintenance des tests est un aspect souvent négligé mais important. Des tests obsolètes ou fragiles ralentissent le développement au lieu de l’accélérer. De bonnes pratiques de maintenance permettent aux tests de rester utiles tout au long de la vie du projet.

1. Stratégie de test pyramidale

La pyramide de tests répartit l’effort de test : beaucoup de tests rapides et fiables à la base, peu de tests lents et fragiles au sommet. Cette répartition optimise le rapport entre couverture et temps d’exécution.

// Tests unitaires (base de la pyramide) - rapides et nombreux 
class BusinessLogicTest { @Test fun 
calculateTotal_withValidItems_returnsCorrectSum() { val items = 
listOf( CartItem("item1", 10.0, 2), CartItem("item2", 15.0, 1) ) 
    val total = ShoppingCart.calculateTotal(items) 
    
    assertEquals(35.0, total, 0.01) 
} 
} 
 
// Tests d'intégration (milieu) - modérément nombreux class 
RepositoryIntegrationTest { @Test fun 
saveAndRetrieveUser_persistsCorrectly() = runTest { val user = 
User("test@example.com", "Test User") 
    repository.saveUser(user) 
    val retrievedUser = repository.getUser(user.email) 
    
    assertEquals(user, retrievedUser) 
} 
} 
 
// Tests UI (sommet) - peu nombreux mais critiques class 
CriticalUserFlowTest { @Test fun purchaseFlow_completesSuccessfully()...