Come eseguire il test Gradle quando tutti i test sono AGGIORNATI?


131

Ho impostato la mia sceneggiatura di livello. Quando eseguo la build Gradle, tutto funziona ed esegue i test jUnit.

Dopodiché quando eseguo il test Gradle ottengo quanto segue:

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

Quando eseguo gradle clean, quindi Gradle build funziona, ovviamente ... Voglio essere in grado di ripristinare solo i test, non di costruire l'intero progetto: come devo fare?


3
Questo sembra inutile, in base alle informazioni fornite. Se né il codice dell'applicazione né il codice test sono stati modificati, perché è necessario rieseguire i test?
Jolta,

10
@Jolta Alcuni dei test nel mio codice sono correlati agli input di 3 parti, sto eseguendo i miei test non solo per assicurarmi di non aver inserito alcun bug all'interno del codice, anche per verificare se qualcosa cambia sugli input di 3 parti che sto ricevendo
USer22999299

4
Mi dispiace essere pignolo, ma non credo che questo sia il modo corretto di pensare a questo: se hai input variabili a 3 parti non è il modo corretto di gestirli per deridere questi input in qualche modo? Il test dovrebbe effettivamente riguardare il test del codice che stai scrivendo. Non sei in evidente pericolo di ottenere falsi positivi se si fa affidamento su input di 3 parti per essere inaccettabili? La strategia non dovrebbe essere quella di soddisfare l'inserimento di problemi come parte del codice dell'app?
mike rodent,

9
@mikerodent considera la possibilità di testare il tuo codice con un servizio online di terze parti. Si desidera monitorare le possibili modifiche nell'API di servizio per poter rispondere con correzioni distribuite al più presto. I test CI non sono un buon modo per farlo? L'uso di un mock ti dirà solo che il tuo codice non ha regressioni, ma le dipendenze potrebbero comunque avere delle modifiche. l'utilizzo del servizio reale indicherebbe che il prodotto può effettivamente eseguire le operazioni previste nell'ambiente attuale.
Elista il

5
Ciò è valido anche dal punto di vista del test di integrazione in cui il punto del test è convalidare l'integrazione del codice con altri bit di codice, dove non sarebbe appropriato prendere in giro le dipendenze
1800 INFORMAZIONI,

Risposte:


172

Un'opzione sarebbe usare il --rerun-tasksflag nella riga di comando . Ciò eseguirà nuovamente tutte le attività di test e tutte le attività da cui dipende.

Se sei interessato solo a rieseguire i test, un'altra opzione sarebbe quella di rendere il gradle clean i risultati dei test prima di eseguire i test. Questo può essere fatto usando l' cleanTestattività.

Alcuni retroscena: il plug-in Java definisce attività pulite per ciascuna delle altre attività. Secondo la documentazione :

cleanTaskName : elimina i file creati dall'attività specificata. cleanJar eliminerà il file JAR creato dall'attività jar e cleanTest eliminerà i risultati del test creati dall'attività test.

Pertanto, tutto ciò che serve per rieseguire i test è eseguire anche l' cleanTestattività, ovvero:
gradle cleanTest test


3
gradle cleanTest testnon riesegue i test, pulisce il loro output, ma l' testattività otterrà comunque i risultati dei test dalla cache - vedi github.com/gradle/gradle/issues/9153
dan.m era user2321368 il

3
Il commento sopra è giusto. Ma se lo usi --no-build-cache, funzionerà come previsto, ad es gradle cleanTest test --no-build-cache.
vRallev,

51

Un'altra opzione sarebbe quella di aggiungere quanto segue nel tuo build.gradle:

test.outputs.upToDateWhen {false}

1
Ho usato questa tecnica per funcTestun'attività che ho creato per eseguire test funzionali.
faringe

4
Questo è un approccio molto migliore rispetto alla risposta accettata, poiché verrà applicato solo all'attività desiderata. La upToDateWhenpuò essere utilizzato in alcun modo "code-driven", come proprietà di sistema, variabili d'ambiente, le proprietà del progetto, ecc
mkobit

1
Come cita la risposta stackoverflow.com/a/52484259/340175 , c'è un utile post sul blog blog.gradle.org/stop-rerunning-tests che spiega perché questo approccio non è raccomandato come approccio generale. Concordo tuttavia sul fatto che possa essere utile e realizzare ciò che pone la domanda.
JulianHarty,

Sì, questa è una risposta datata, quando ho scritto che questo Gradle era alla versione 2.11 e ho appena iniziato a essere utilizzabile, ma aveva ancora molti spigoli, che sono stati lucidati oggi.
František Hartman,

1
Bella risposta!!! Superato utilizzando un parametro: gradle test -Prerun-tests. Codice in build.gradle:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
AlikElzin-kilaka


17

Recentemente questo è stato l'argomento sul post sul blog di Gradle Smetti di ripetere i tuoi test . L' autore mostra un esempio usando outputs.upToDateWhen { false }e spiega perché è sbagliato:

Questo in realtà non forza le repliche

Ciò che l'autore di questo frammento probabilmente ha voluto dire è "Rieseguire sempre i miei test". Questo non è ciò che fa questo frammento. Contrassegna solo l'attività non aggiornata, costringendo Gradle a ricreare l'output. Ma ecco il punto, se la cache di build è abilitata, Gradle non ha bisogno di eseguire l'attività per ricreare l'output. Troverà una voce nella cache e decomprimerà il risultato nella directory di output del test.

Lo stesso vale per questo frammento:

test.dependsOn cleanTest

Gradle decomprimerà i risultati del test dalla cache di build dopo che l'output è stato pulito, quindi non verrà eseguito nuovamente nulla. In breve, questi frammenti stanno creando una no-op molto costosa.

Se ora stai pensando "Ok, anch'io disattiverò la cache", lascia che ti dica perché non dovresti.

Quindi, l'autore continua spiegando perché rieseguire alcuni test è una perdita di tempo:

La stragrande maggioranza dei test dovrebbe essere deterministica, ovvero, dati gli stessi input, dovrebbero produrre lo stesso risultato.

Nei pochi casi in cui si desidera rieseguire i test in cui il codice non è stato modificato, è necessario modellarli come input. Ecco entrambi gli esempi del post sul blog che mostrano l'aggiunta di un input in modo che l'attività lo utilizzi durante i suoi controlli aggiornati.

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

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

Consiglio di leggere l'intero post del blog.


8
Questo sembra ottimo per il caso d'uso specifico di cui stai parlando, ma sto scrivendo test post-implementazione su un servizio web esterno dal vivo e mi capita di usare junit e gradle per ottenere questo risultato. Il codice sottoposto a test non risiede nel repository e in effetti non esiste un "codice applicazione" perché in realtà sto testando un sistema di produzione live anziché il codice stesso. Grazie per la risposta, questo è molto utile! Volevo solo sottolineare che ci sono altri casi d'uso che richiedono di ripetere i test ogni volta anche se nessuno dei gradi di codice che sa sta cambiando
Brandon,

11

Ecco una soluzione che utilizza il file "build.gradle", nel caso in cui non si desideri modificare la riga di comando:

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

Ed ecco l'output. Notare 2 modifiche rispetto all'output precedente:

1) Nell'output viene visualizzata una nuova attività "cleanTest".

2) 'test' viene sempre pulito (cioè mai 'UP-TO-DATE') quindi viene eseguito ogni volta:

$ 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

1
l'esecuzione cleanTestprima testnon eseguirà nuovamente i test, pulirà il loro output, ma l'attività di test otterrà comunque i risultati del test dalla cache - consultare github.com/gradle/gradle/issues/9153
dan.m era user2321368

8

--rerun-tasks funziona, ma è inefficiente in quanto esegue nuovamente tutte le attività.

cleanTest di per sé potrebbe non essere sufficiente a causa della compilazione della cache.

quindi, il modo migliore per raggiungere questo obiettivo è:

./gradlew --no-build-cache cleanTest test

0

Inoltre, dover aggiungere --rerun-tasksè davvero ridondante. Non succede mai Crea un --no-rerun-taskse rendi --rerun-taskspredefinito quandocleanTask



-4

Penso che questa sia una domanda valida dato che in Gradle è possibile eseguire questo comando test e ciò che accade è che non succede nulla!

Ma metterei in dubbio la necessità di farlo, come ha detto Jolta nel suo commento: se nessun codice è cambiato, perché è necessario ripetere il test? Se hai dubbi sugli input di terze parti, direi che devi provvedere a questo nel tuo codice dell'app. Se temi che il tuo codice possa essere "instabile", ovvero in grado di superare tutti i test la prima volta ma non una seconda (o la centesima volta), non hai bisogno di pensare al motivo per cui hai questi dubbi e di affrontarli?

Personalmente penso che questo sia un errore di progettazione (molto minore) in Gradle: se tutto è completamente aggiornato, piuttosto che andare "BUILD SUCCESSFUL" dovrebbe dire "NESSUN CAMBIAMENTO DALL'ULTIMO SUCCESSFIL BUILD: NULLA FATTO".


3
"Non hai bisogno di pensare al motivo per cui hai questi dubbi e di affrontarli?": Sì, ma per ottenere dati a cui pensare, vorrei eseguire i test alcune volte e vedere cosa succede. È così pazzo?
mhsmith,

1
@mikerodent Sono parzialmente d'accordo con il tuo punto. Ci sono casi "facili", in genere semplici test di unità whitebox, in cui nessuna modifica del codice non significa nulla da ripetere. Pensa ai test con dipendenze però. "Oh sì, la finestra mobile non funzionava ecc." Ci sono test in cui è l'infrastruttura (e in sviluppo) che imposta le dipendenze (sono "fornite") e non la build. In questi casi, voglio sempre essere in grado di rieseguirlo.
dbalakirev,

@dbalakirev Sì, mi è venuto in mente ... ma non dovresti essere in grado di deridere il ruolo di queste dipendenze, come Docker ...? Voglio dire, se non lo fai, non stai accumulando problemi futuri? Non sto dicendo di essere sicuro al 100%, ma quello che penso di dire è che i tuoi test dovrebbero, in un mondo senza dubbio più ideale dei nostri, coprire tutte le basi.
mike rodent,

Puoi deridere sì, con il quale hai una dipendenza (finestra mobile) che se fallisce su di te significa che vuoi rieseguire anche se il codice non è cambiato. Vorrei sottolineare che questo pensiero non è per test unitari o test in cui 1. si tenta di evitare le dipendenze 2. o almeno li deridono utilizzando il framework di test, ma quando sono realmente "forniti", se lo si desidera.
dbalakirev,

2
__ se nessun codice è cambiato, perché è necessario ripetere il test? __ Hai sentito parlare dei test di integrazione?
Bogdan Mart,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.