Tutoriel pour apprendre à tester son application Android avec MockK

MockK est une bibliothèque permettant de créer des mocks de classes Kotlin. Alors pourquoi ne pas utiliser des bibliothèques bien plus connues dans le monde Android comme Mockito par exemple ? ¯\(°_o)/¯

Tout simplement parce que par défaut les classes Kotlin sont finales. Tel quel, Mockito ne permet pas de mocker les classes finales.

L’objectif de cet article est donc de vous présenter cette récente bibliothèque.

Prérequis pour la lecture de cet article :

  • Android Studio ;
  • Kotlin ;
  • Junit ;
  • tests unitaires.

Pour réagir au contenu de cet article, un espace de dialogue vous est proposé sur le forum : Commentez Donner une note  l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Partons du principe que vous écrivez un code dont la fonctionnalité consiste à récupérer des utilisateurs stockés sur un serveur puis de les afficher dans une liste. Comment s’assurer que le code que vous avez écrit fonctionne bien ?

Ci-dessous un exemple d’une telle fonctionnalité.


Note : à la fin de cet article dans les liens externes, vous pourrez télécharger le modèle d’application dont cet exemple est issu.

UserViewModel.kt
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
class UserViewModel(application: Application,
                   private val networkService: NetworkService): ViewModel(application)
{
   @get:Bindable
   var user: List<User> by Delegates.observable(listOf()) { _, _, _ ->  notifyPropertyChanged(BR.user) }
   fun requestData()
   {
       networkService.getUsers {
           when (it)
           {
               is NetworkService.UserError.UserFetched -> user = it.user
               else ->{}
           }
       }
   }
}

Comme vous pouvez le voir dans l’exemple précédent, la classe UserViewModel possède une méthode requestData. Lors de l’appel à celle-ci, elle demande au NetworkService de récupérer la liste de tous les utilisateurs via la méthode getUsers. Cette méthode ne retourne rien, mais reçoit en paramètre une lambda qui contiendra les résultats.

Il y a deux possibilités pour tester ce code :

  1. Installer et lancer l’application sur un téléphone (ou un émulateur) puis appuyer sur l’élément graphique permettant de lancer la fonctionnalité ;
  2. Écrire un programme pour tester spécifiquement la fonctionnalité.

Dans cet article, nous allons nous intéresser à cette deuxième possibilité. Elle consiste à écrire un test unitaire en simulant le comportement des objets dont on dépend.

II. Les mocks : simuler le comportement des classes dont on dépend

Comme le mentionne cette page du site, les mocks permettent d’isoler la classe que vous souhaitez tester unitairement en contrôlant le comportement de vos dépendances.

De ce fait vous isolez complètement votre classe et ne testez que son comportement.

II-A. MockK : une bibliothèque de mock pour Kotlin

II-B. Comment installer MockK dans votre projet Android

build.gradle
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
// Dans le fichier build.gradle de votre projet

buildscript {
    // Ajoutez la variable : mockkVersion
    ext {
        // Version actuelle de mockK lors de l’écriture de cet article
        mockkVersion = '1.9.3'
    }
}
app/build.gradle
Sélectionnez
1.
2.
3.
4.
5.
6.
// Dans le fichier build.gradle de votre module Android Studio

dependencies {
    // Ajoutez la dépendance à mockK
    testImplementation "io.mockk:mockk:$mockkVersion"
}

Ces deux fichiers permettent d’ajouter la bibliothèque Mockk dans votre projet en deux étapes :

  1. Créer la variable mockkVersion. Cette étape n’est pas obligatoire, mais permet de rendre votre projet plus visible si vous avez de multiples dépendances externes ;
  2. Ajouter concrètement la dépendance à Mockk en fonction de la version précédemment créée.

II-C. UserViewModelTest : la classe testant unitairement le UserViewModel

Pour créer la classe UserViewModelTest, je vous conseille d’utiliser les fonctionnalités d’Android Studio. Ce dernier se chargera de créer le fichier au bon endroit et avec le bon package.

Pour cela : clic droit sur le nom de la classe / générer / test.

UserViewModelTest.kt
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
class UserViewModelTest {
   //Annotation de MockK permettant de créer automatiquement un mock
   @MockK
   private lateinit var application: Application
   @MockK
   private lateinit var networkService: NetworkService

   //Annotation de MockK permettant d’injecter automatiquement le mock à notre viewModel
   @InjectMockKs
   private lateinit var viewModel: UserViewModel

   //Annotation de JUnit permettant d’appeler la méthode setUp() avant chaque test
   @Before
   fun setUp() = MockKAnnotations.init(this)

   //Annotation permettant d’indiquer à JUnit que la méthode est un cas de test
   @Test
   fun `requestData() doit transmettre la requête au networkService`() {
       //On définit le comportement de notre mock. Ici on spécifie : “qu’à chaque fois que la méthode getUser() sera appelée avec n’importe quoi en paramètre → on ne fera rien”
       every { networkService.getUsers(any()) } just Runs

       //On appelle la méthode de notre viewModel
       viewModel.requestData()

       //On vérifie que la méthode getUser() a bien été appelée
       verify { networkService.getUsers(any()) }
   }
}

Dans cet exemple, l’objectif est de vérifier qu’une méthode de notre mock a bien été appelée.

Pour cela les différentes étapes ont été les suivantes :

  1. Création des différents mocks en utilisant l’annotation @Mockk ;
  2. Injection des mocks créés dans la classe à tester @InjectMockks ;
  3. Définition du comportement de nos mocks : every{…} ;
  4. Appel de la méthode de notre classe à tester : viewModel.requestData() ;
  5. Vérification que la méthode de notre mock a bien été appelée : verify{...}.

II-D. Résultats des tests de UserViewModelTest 

Lors de l’exécution de UserViewModelTest, volontairement j’ai fait échouer puis réussir les tests unitaires. Les deux images suivantes vous montrent cela :

Image non disponible
Image non disponible

III. Conclusion et remerciements

Cet article vous a donné un aperçu des possibilités de mockK. Elles sont nombreuses et je ne pouvais pas tout énumérer ici.

Je vous invite donc à parcourir la documentation pour avoir une idée de la puissance cette bibliothèque.

Toutefois une liste non exhaustive des fonctionnalités les plus utilisées à mon sens serait :

  • la possibilité de mocker des lambdas ;
  • par défaut les mocks créés par MockK sont stricts. Cela signifie que toutes les méthodes doivent avoir été définies via every{…}. Pour éviter cela, MockK permet l’utilisation de RelaxedMock ;
  • la possibilité de capturer les paramètres d’une fonction. Cette fonctionnalité est très utilisée dans le cas d’une fonction A ayant comme paramètre une autre fonction B. Les mots clefs MockK pour faire cela sont : capture et slot ;
  • dans cet article nous avons pris un cas simple dans lequel on a vérifié que la méthode de notre mock a bien été appelée : networkService.getUsers().
    Toutefois Mockk permet des vérifications plus avancées telles que : vérifier le nombre de fois qu’une méthode a été appelée (verify {atLeast = … / atMost = … / exactly = … }, vérifier l’appel à une méthode en lui spécifiant un timeout : verify {timeout = … }.

Je tiens à remercier Mickael Baron pour sa relecture technique et la mise au gabarit ainsi que Claude Leloup pour sa relecture orthographique attentive de cet article.

IV. Liens externes pour aller plus loin

Télécharger la structure de l’application Android dont sont issus ces exemples.

La documentation de MockK (en anglais).

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2020 Sanders. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.