Comment exécuter le test Gradle lorsque tous les tests sont À JOUR?

131

J'ai configuré mon script de note. Lorsque j'exécute la compilation Gradle, tout fonctionne et il exécute les tests jUnit.

Après cela, lorsque j'exécute le test Gradle, j'obtiens ce qui suit:

C:\Users\..\..\Project>gradle test
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE

Quand j'exécute gradle clean, alors Gradle build fonctionne, bien sûr ... Je veux pouvoir réinitialiser uniquement les tests, pas construire tout le projet: comment dois-je faire cela?

USer22999299
la source
3
Cela semble inutile, sur la base des informations fournies. Si ni le code de l'application ni le code de test n'ont changé, pourquoi devez-vous réexécuter les tests?
Jolta
10
@Jolta Certains des tests de mon code sont liés à des entrées tierces, j'exécute mes tests non seulement pour m'assurer que je n'ai pas mis de bogue dans le code, mais également pour vérifier si quelque chose change sur les entrées tierces que je reçois
USer22999299
4
Désolé d'être pointilleux, mais je ne pense pas vraiment que ce soit la bonne façon de penser à ce sujet: si vous avez des entrées tierces variables, n'est-ce pas la bonne façon de gérer cela pour se moquer de ces entrées d'une manière ou d'une autre? Le test devrait en fait être le test du code que vous écrivez. N'êtes-vous pas en danger assez évident d'obtenir des faux positifs si vous vous fiez à une entrée tierce pour être inacceptable? La stratégie ne devrait-elle pas être de prendre en charge la saisie des problèmes dans le code de votre application?
mike rodent
9
@mikerodent envisage de tester votre code par rapport à un service en ligne tiers. Vous souhaitez surveiller les modifications possibles dans l'API de service pour pouvoir répondre avec les correctifs déployés dès que possible. Les tests CI ne sont-ils pas un bon moyen d'y parvenir? L'utilisation d'un simulacre vous indiquera seulement que votre propre code n'a pas de régressions, mais que les dépendances peuvent encore avoir des modifications. l'utilisation du service réel indiquerait que votre produit peut réellement effectuer les opérations attendues dans l'environnement actuel.
Elist
5
Ceci est également valable d'un point de vue du test d'intégration où le but du test est de valider l'intégration de votre code avec d'autres bits de code, là où il ne serait pas approprié de se moquer dans les dépendances
1800 INFORMATION

Réponses:

172

Une option serait d'utiliser l' --rerun-tasksindicateur dans la ligne de commande . Cela réexécuterait toute la tâche de test et toutes les tâches dont elle dépend.

Si vous souhaitez uniquement réexécuter les tests, une autre option serait de faire en sorte que gradle nettoie les résultats des tests avant d'exécuter les tests. Cela peut être fait en utilisant la cleanTesttâche.

Un peu de contexte - le plugin Java définit des tâches propres pour chacune des autres tâches. Selon la documentation :

cleanTaskName - Supprime les fichiers créés par la tâche spécifiée. cleanJar supprimera le fichier JAR créé par la tâche jar et cleanTest supprimera les résultats de test créés par la tâche de test.

Par conséquent, tout ce dont vous avez besoin pour réexécuter vos tests est d'exécuter également la cleanTesttâche, c'est-à-dire:
gradle cleanTest test

Amnon Shochot
la source
3
gradle cleanTest testne réexécute pas les tests, il nettoie leur sortie, mais la testtâche obtiendra toujours les résultats des tests du cache - voir github.com/gradle/gradle/issues/9153
dan.m était user2321368
3
Le commentaire ci-dessus est juste. Mais si vous utilisez --no-build-cache, cela fonctionnera comme prévu, par exemple gradle cleanTest test --no-build-cache.
vRallev le
51

Une autre option serait d'ajouter ce qui suit dans votre build.gradle:

test.outputs.upToDateWhen {false}
František Hartman
la source
1
J'ai utilisé cette technique pour une funcTesttâche que j'ai créée pour exécuter des tests fonctionnels.
pharsicle
4
C'est une bien meilleure approche que la réponse acceptée, car elle ne sera appliquée qu'à la tâche souhaitée. Le upToDateWhenpeut être utilisé de n'importe quelle manière "pilotée par le code", comme les propriétés système, les variables d'environnement, les propriétés du projet, etc.
mkobit
1
Comme le mentionne la réponse stackoverflow.com/a/52484259/340175 , il existe un article de blog utile blog.gradle.org/stop-rerunning-tests qui explique pourquoi cette approche n'est pas recommandée comme approche générale. Je conviens cependant que cela peut être utile et répond à ce que la question demande.
JulianHarty
Oui, c'est une réponse datée, quand j'ai écrit ce Gradle était à la version 2.11 et commençait juste à être utilisable, mais avait encore de nombreux bords rugueux, qui sont polis aujourd'hui.
František Hartman
1
Très bonne réponse!!! Passé à l'aide d' un paramètre: gradle test -Prerun-tests. Code dans build.gradle:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
AlikElzin-kilaka
17

C'était récemment le sujet du billet de blog de Gradle Arrêtez de réexécuter vos tests . L' auteur montre un exemple d'utilisation outputs.upToDateWhen { false }et explique pourquoi c'est faux:

Cela ne force pas réellement les rediffusions

Ce que l'auteur de cet extrait de code voulait probablement dire, c'est "Toujours réexécuter mes tests". Ce n'est pas ce que fait cet extrait de code. Cela marquera uniquement la tâche obsolète, forçant Gradle à recréer la sortie. Mais voici le problème, si le cache de construction est activé, Gradle n'a pas besoin d'exécuter la tâche pour recréer la sortie. Il trouvera une entrée dans le cache et décompressera le résultat dans le répertoire de sortie du test.

La même chose est vraie pour cet extrait:

test.dependsOn cleanTest

Gradle décompressera les résultats du test du cache de compilation une fois la sortie nettoyée, donc rien ne sera réexécuté. En bref, ces extraits créent un no-op très coûteux.

Si vous pensez maintenant «OK, je vais désactiver le cache aussi», laissez-moi vous dire pourquoi vous ne devriez pas.

Ensuite, l'auteur explique pourquoi réexécuter certains tests est une perte de temps:

La grande majorité de vos tests doivent être déterministes, c'est-à-dire, étant donné les mêmes entrées, ils devraient produire le même résultat.

Dans les quelques cas où vous souhaitez réexécuter des tests où le code n'a pas changé, vous devez les modéliser comme une entrée. Voici deux exemples du billet de blog qui montrent l'ajout d'une entrée afin que la tâche l'utilise lors de ses vérifications à jour.

task randomizedTest(type: Test) {
  systemProperty "random.testing.seed", new Random().nextInt()
}

task systemIntegrationTest(type: Test) {
  inputs.property "integration.date", LocalDate.now()
}

Je recommande de lire l'intégralité du billet de blog.

mkobit
la source
8
Cela semble très bien pour le cas d'utilisation spécifique dont vous parlez, mais j'écris des tests post-déploiement sur un service Web externe en direct et j'utilise simplement junit et gradle pour y parvenir. Le code testé ne vit pas dans le référentiel, et en fait il n'y a pas de «code d'application» car je teste en fait un système de production en direct plutôt que le code lui-même. Merci pour la réponse, c'est très utile! Je voulais juste souligner qu'il existe des cas d'utilisation supplémentaires qui nécessitent de réexécuter les tests à chaque fois, même si aucun des gradeurs de code ne sait changer
Brandon
11

Voici une solution utilisant le fichier "build.gradle", au cas où vous ne voudriez pas modifier votre ligne de commande:

test {
    dependsOn 'cleanTest'
    //Your previous task details (if any)
}

Et voici la sortie. Notez 2 changements par rapport à votre sortie précédente:

1) Une nouvelle tâche «cleanTest» apparaît dans la sortie.

2) 'test' est toujours nettoyé (c'est-à-dire jamais 'UP-TO-DATE') donc il est exécuté à chaque fois:

$ gradle build
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:findMainClass
:jar
:bootRepackage
:assemble
:cleanTest
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test
:check
:build
TealSeed
la source
1
en cours d'exécution cleanTestavant testne réexécutera pas les tests, il nettoie leur sortie, mais la tâche de test obtiendra toujours les résultats des tests du cache - voir github.com/gradle/gradle/issues/9153
dan.m était user2321368
8

--rerun-tasks fonctionne, mais est inefficace car il réexécute toutes les tâches.

cleanTest à lui seul peut ne pas suffire en raison de la création du cache.

donc, la meilleure façon d'y parvenir est:

./gradlew --no-build-cache cleanTest test
masc3d
la source
0

De plus, avoir à ajouter --rerun-tasksest vraiment redondant. Cela n'arrive jamais. Créez un --no-rerun-taskset définissez-le --rerun-taskspar défaut lorsquecleanTask

user1648995
la source
-1

TL; DR

test.dependsOn cleanTest
Topera
la source
2
Selon stackoverflow.com/a/52484259/466862, cela ne fonctionnera pas.
Mark Rotteveel
Eh bien, les documents de gradle sont un peu déroutants .... Ici, ils disent que cleanTest peut être utilisé à cette fin. docs.gradle.org/current/userguide/… . Et aussi, cela fonctionne sur ma machine (et gradle version 4.10.3);)
Topera
-4

Je pense que c'est une question valable étant donné qu'il est possible dans Gradle d'exécuter cette commande test, et ce qui se passe, c'est que rien ne se passe!

Mais je remettrais en question la nécessité de faire cela, comme Jolta l'a dit dans son commentaire: si aucun code n'a changé, pourquoi avez-vous besoin de re-tester? Si vous avez des doutes sur les entrées tierces, je dirais que vous devez en tenir compte dans le code de votre application. Si vous craignez que votre code ne soit "floconneux", c'est-à-dire capable de passer tous les tests une première fois mais pas une seconde (ou une centième fois), n'avez-vous pas besoin de réfléchir aux raisons pour lesquelles vous avez ces doutes, et de les résoudre?

Personnellement, je pense que c'est un défaut de conception (très mineur) dans Gradle: si tout est complètement à jour, plutôt que de passer à "BUILD SUCCESSFUL", il devrait dire "NO CHANGE SINCE DERNIER SUCCESSFUL BUILD: RIEN FAIT".

Mike rongeur
la source
3
"N'avez-vous pas besoin de réfléchir à la raison pour laquelle vous avez ces doutes, et de les résoudre?": Oui, mais pour avoir des données à réfléchir, j'aimerais exécuter les tests plusieurs fois et voir ce qui se passe. Est-ce si fou?
mhsmith
1
@mikerodent Je suis partiellement d'accord avec votre point de vue. Il existe des cas «faciles», généralement de simples tests unitaires en boîte blanche, où aucun changement de code ne signifie vraiment rien à re-tester. Pensez cependant aux tests avec dépendances. "Oh ouais, docker ne fonctionnait pas, etc." Il y a des tests où c'est l'infrastructure (et en développement vous) qui met en place les dépendances (elles sont "fournies") et non la construction. Dans ces cas, je veux toujours pouvoir recommencer.
dbalakirev
@dbalakirev Oui, cela m'est venu à l'esprit ... mais ne devriez-vous pas pouvoir vous moquer du rôle de ces dépendances, comme Docker ...? Je veux dire, si vous ne faites pas ça, n'empêchez-vous pas de futurs problèmes? Je ne dis pas que je suis sûr à 100%, mais ce que je pense que je dis, c'est que vos tests devraient, dans un monde sans doute plus idéal que le nôtre, couvrir toutes les bases.
mike rodent
Vous pouvez vous moquer de oui, avec lequel vous avez une dépendance (docker) qui si elle échoue, cela signifie que vous souhaitez réexécuter même si le code n'a pas changé. Je voudrais souligner que cette pensée n'est pas pour les tests unitaires ou les tests où 1. vous essayez d'éviter les dépendances 2. ou du moins les moquer en utilisant le framework de test, mais quand ils sont vraiment "fournis" si vous voulez.
dbalakirev
2
__ si aucun code n'a changé, pourquoi devez-vous effectuer un nouveau test? __ Avez-vous entendu parler des tests d'intégration?
Bogdan Mart