Accélérez vos tests Android Espresso en regroupant les tests pertinents
Si vous êtes comme moi, vous l’aimez quand il y a un seul bouton pour appuyer sur ce que je veux. En ce qui concerne l’exécution de tests dans Android Studio, j’aime qu’il soit facile de le configurer pour exécuter tous mes tests avec le bouton Exécuter. Cependant, lorsque le nombre et la complexité des tests augmentent avec le temps, les actions derrière ce bouton peuvent prendre beaucoup plus de temps que je le souhaiterais, surtout s’il s’agit de tester le code d’application avec lequel je ne travaille pas actuellement.
Pourquoi courir tout tests tout du temps, quand vous voulez vraiment exécuter ceux qui comptent maintenant? Ou du moins ceux qui courent rapidement. Heureusement, les outils de test Android vous permettent de découper vos tests en groupes associés pour des tests plus rapides. Voici vos options.
J’ai mis « taille » entre guillemets ici, car ce n’est pas ce que vous pensiez au départ. Ce n’est pas tant le volume de code dans le test, mais ce qu’il fait qui pourrait le ralentir. Les outils de test Android vous proposent trois catégories de taille: petite, moyenne et grande. Pour insérer un test dans chaque catégorie, utilisez l’une des annotations fournies (@SmallTest
, @MediumTest
, @LargeTest
) sur une méthode de test individuelle ou sur la classe qui contient les méthodes de test (auquel cas, elle s’applique à toutes les méthodes de test contenues). Voici un exemple:
@SmallTest
fun testSomethingSimple() {
// Test code...
}
Vous pouvez voir ici que la méthode de test individuelle testSomethingSimple
est annoté avec @SmallTest
. À en juger par son nom, il semble être un bon candidat pour un soi-disant «petit test», mais que signifie réellement cette catégorie de taille? En fait, ils ont des descriptions très spécifiques, et je suggère de cliquer pour lire la documentation de l’API pour chacun. Résumer:
- Petits tests ne fais pas d’E / S du tout, et devrait fonctionner moins de 200 ms.
- Tests moyens peut utiliser des fichiers et des bases de données locaux, mais pas en réseau, et devrait fonctionner moins de 1000 ms.
- Grands tests peut tout utiliser, y compris les données locales et distantes, pour tester l’intégration complète de l’application.
Si vos tests lancent votre application et se poursuivent réel les cas d’utilisation, l’accès aux données à partir d’API et de bases de données distantes, ils sont probablement tous classés comme des tests volumineux. Pour classer un test comme petit ou moyen, vous devrez peut-être rechercher des stratégies pour simuler, simuler ou bloquer le code qui effectue les E / S. Cela peut être un travail considérable à mettre en place si vous n’utilisez pas déjà une certaine forme d’injection de dépendance. Mais je dirai que, idéalement, vous voudrez probablement que le plus grand nombre de vos tests soient «petits», même si cela nécessite un effort d’ingénierie supplémentaire. Le stubbing, la simulation et la simulation de données distantes pendant les tests peuvent accélérer considérablement le retour d’informations de vos tests pendant le développement. Cependant, la mise en œuvre efficace est un tout nouveau sujet!
Supposons que vous ayez maintenant des tests classés par taille. Afin d’accélérer vos cycles de développement et de test, vous souhaiterez peut-être exécuter uniquement de petits tests, pour obtenir rapidement des informations sur le fonctionnement de votre nouveau code, et cela n’a rien cassé immédiatement. Ce que vous devrez faire, c’est prendre des dispositions pour passer la «taille» option au lanceur de test instrumenté Android en utilisant -e size small
. Vous pouvez ajouter cela à build.gradle sous defaultConfig
comme ça:
android {
defaultConfig {
testInstrumentationRunnerArguments size: 'small'
}
}
Mais vous ne voulez probablement pas en faire une partie permanente de la construction. Au lieu de cela, vous pouvez passer cette directive via la ligne de commande Gradle comme ceci:
-Pandroid.testInstrumentationRunnerArguments.size=small
Avec cela, seuls les tests annotés avec @SmallTest
va fonctionner. C’est bien pour un regroupement horizontal, par taille, mais qu’en est-il verticalement, par caractéristique du produit?
Supposons que vous travaillez sur une seule fonctionnalité de votre application et que vous connaissez très bien l’ensemble de code exécuté avec cette fonctionnalité. Au lieu d’exécuter tous les tests de votre application, vous souhaiterez peut-être exécuter uniquement les tests qui exercent cette fonctionnalité. Une façon de le faire est suite de tests. Une suite de tests vous permet de définir un groupe de classes de tests qui doivent être exécutées ensemble à la demande, sans avoir à les exécuter individuellement.
Tout ce que vous avez à faire est de définir une classe vide et de lui donner deux annotations, @RunWith
et @SuiteClasses
. Voici une suite simple appelée TestSuite
:
import org.junit.runner.RunWith
import org.junit.runners.Suite
import org.junit.runners.Suite.SuiteClasses@RunWith(Suite::class)
@SuiteClasses(Activity01Test::class, Activity02Test::class)
class TestSuite
@RunWith
indique au lanceur de test qu’il s’agit d’une suite, et @SuiteClasses
répertorie toutes les classes de test qui composent cette suite. Lorsque le coureur rencontre cette classe, il exécute les tests dans toutes les classes nommées. Vous devrez vous arranger pour utiliser cette classe comme vous le feriez pour n’importe quelle autre classe, en passant -e class package.of.TestSuite01
au coureur d’instrumentation. Vous pouvez ajouter cela à build.gradle sous defaultConfig
comme ceci en utilisant son nom complet de classe:
android {
defaultConfig {
testInstrumentationRunnerArguments class: 'pkg.of.TestSuite'
}
}
Ou via la ligne de commande Gradle comme ceci:
-Pandroid.testInstrumentationRunnerArguments.class=pkg.of.TestSuite
Il y a une chose à savoir sur les suites de tests. Si vous ajoutez une classe de suite de tests à votre collection de tests et choisissez d’exécuter tout tests, votre suite de tests s’exécutera en plus de tous les autres tests. Imaginez une disposition de package comme celle-ci:
Ce que nous avons ici est des classes de test définies dans le package my.testapp
et une suite définie dans my.testapp.suite
qui utilise certaines des classes de my.testapp
. Si vous choisissez de courir tout tests pour ce projet, ou même tous les tests en package my.testapp
, la suite dupliquera l’effort de ses classes nommées et ralentira inutilement les choses. Pour éviter cela, organisez votre suite et testez les classes en différents packages qui ne sont pas imbriqués:
Avec cela, nous pouvons choisir d’exécuter tous les tests dans le package my.testapp.classes
séparément de la suite en passant -e package my.testapp.classes
via build.gradle:
testInstrumentationRunnerArguments package: 'my.testapp.classes'
Ou la ligne de commande:
-Pandroid.testInstrumentationRunnerArguments.package=my.testapp.classes
Les suites de tests sont un bon moyen de regrouper les tests par certaines fonctionnalités communes, mais cela nécessite que vous les listiez tous dans une seule classe. Cela peut ne pas être très pratique et les longues listes peuvent être difficiles à gérer. Il peut être plus facile de marquer chaque classe ou méthode de test comme faisant partie d’un groupe à exécuter ensemble. Pour ce faire, vous pouvez créer une annotation personnalisée et l’utiliser pour marquer les classes et méthodes à exécuter. Par exemple, voici une déclaration d’annotation simple:
package my.testappannotation class FeatureTest
Ensuite, vous pouvez l’appliquer à une classe de test ou à une méthode individuelle:
@RunWith(AndroidJUnit4::class)
@FeatureTest
class Feature01Test {
// test methods here
}
Une fois que vous avez des classes et des méthodes marquées comme ceci, vous pouvez ensuite passer un argument au lanceur de test pour indiquer que seuls ces tests marqués doivent s’exécuter, en utilisant -e annotation my.testapp.FeatureTest
. Dans build.gradle, vous utiliseriez ceci:
testInstrumentationRunnerArguments annotation:
'my.testapp.FeatureTest'
Et sur la ligne de commande, comme ceci:
-Pandroid.testInstrumentationRunnerArguments.annotation=my.testapp.FeatureTest
Notez que cette méthode d’utilisation des annotations n’est pas mentionnée dans le documentation formelle sur la ligne de commande du testeur, mais vous pouvez le voir dans la documentation de l’API pour AndroidJUnitRunner.
Le regroupement des tests peut accélérer efficacement vos cycles de développement en vous donnant un moyen d’exécuter uniquement les tests importants pour ce sur quoi vous travaillez actuellement, ou uniquement les tests que vous avez le temps d’exécuter. Cela pourrait également accélérer la façon dont vous effectuez les tests dans les environnements CI. Par exemple, vous souhaiterez peut-être exécuter uniquement des tests plus rapides avec chaque validation et des tests plus lents pendant la nuit. Ou, sur une branche de fonctionnalité, vous pouvez limiter les tests CI à la fonctionnalité en cours de développement uniquement.