Jak uruchomić test Gradle, gdy wszystkie testy są aktualne?

130

Mam skonfigurowany skrypt ocen. Kiedy wykonuję kompilację Gradle, wszystko działa i uruchamia testy jUnit.

Po tym, gdy uruchamiam test Gradle, otrzymuję następujące informacje:

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

Kiedy wykonuję gradle clean, to oczywiście Gradle działa ... Chcę mieć możliwość resetowania tylko testów, a nie budowania całego projektu: jak mam to zrobić?

USer22999299
źródło
3
Biorąc pod uwagę podane informacje, wydaje się to niepotrzebne. Jeśli ani kod aplikacji, ani kod testowy nie uległy zmianie, dlaczego musisz ponownie uruchomić testy?
Jolta
10
@Jolta Niektóre testy w moim kodzie są powiązane z danymi wejściowymi firm zewnętrznych, przeprowadzam testy nie tylko po to, aby upewnić się, że nie umieściłem żadnego błędu w kodzie, ale także po to, aby sprawdzić, czy coś się zmieniło na wejściach stron trzecich co dostaję
USer22999299
4
Przepraszam, że jestem wybredny, ale nie sądzę, aby to był właściwy sposób myślenia o tym: jeśli masz zmienne dane wejściowe stron trzecich, czy nie jest właściwym sposobem radzenia sobie z tym, aby w jakiś sposób kpić z tych danych wejściowych? Testowanie powinno w rzeczywistości polegać na testowaniu kodu, który piszesz. Czy nie jesteś w dość oczywistym niebezpieczeństwie uzyskania fałszywych alarmów, jeśli polegasz na tym, że dane wejściowe stron trzecich są nie do przyjęcia? Czy strategia nie powinna polegać na rozwiązywaniu problemów w ramach kodu aplikacji?
mike gryzoń
9
@mikerodent rozważ przetestowanie kodu w usłudze online innej firmy. Chcesz monitorować możliwe zmiany w interfejsie API usługi, aby móc jak najszybciej odpowiadać za pomocą wdrożonych poprawek. Czy testy CI nie są dobrym sposobem na to? Użycie makiety powie ci tylko, że twój własny kod nie ma regresji, ale zależności nadal mogą mieć zmiany. użycie prawdziwej usługi wskazywałoby, że Twój produkt może faktycznie wykonywać oczekiwane operacje w obecnym środowisku.
Elist
5
Jest to również ważne z punktu widzenia testów integracyjnych, gdzie celem testu jest sprawdzenie integracji twojego kodu z innymi bitami kodu, gdzie nie byłoby właściwe mockowanie w zależnościach
1800 INFORMACJE

Odpowiedzi:

171

Jedną z opcji byłoby użycie --rerun-tasksflagi w wierszu poleceń . Spowoduje to ponowne uruchomienie wszystkich zadań testowych i wszystkich zadań, od których zależy.

Jeśli jesteś zainteresowany tylko ponownym uruchomieniem testów, inną opcją byłoby wyczyszczenie wyników testów przez gradle przed wykonaniem testów. Można to zrobić za pomocą cleanTestzadania.

Trochę tła - wtyczka Java definiuje czyste zadania dla każdego z pozostałych zadań. Zgodnie z dokumentacją :

cleanTaskName - usuwa pliki utworzone przez określone zadanie. cleanJar usunie plik JAR utworzony przez zadanie jar, a cleanTest usunie wyniki testu utworzone przez zadanie testowe.

W związku z tym, aby ponownie uruchomić testy, wystarczy uruchomić również cleanTestzadanie, czyli:
gradle cleanTest test

Amnon Shochot
źródło
3
gradle cleanTest testnie uruchamia ponownie testów, czyści ich dane wyjściowe, ale testzadanie nadal będzie pobierać wyniki testów z pamięci podręcznej - patrz github.com/gradle/gradle/issues/9153
dan.m was user2321368
3
Powyższy komentarz jest słuszny. Ale jeśli używasz --no-build-cache, to zadziała zgodnie z oczekiwaniami, np gradle cleanTest test --no-build-cache.
vRallev
51

Inną opcją byłoby dodanie następującego polecenia w pliku build.gradle:

test.outputs.upToDateWhen {false}
František Hartman
źródło
1
Użyłem tej techniki do funcTestzadania, które stworzyłem, aby uruchomić testy funkcjonalne.
farsicle
4
Jest to znacznie lepsze podejście niż zaakceptowana odpowiedź, ponieważ zostanie zastosowane tylko do pożądanego zadania. upToDateWhenMoże być stosowany w każdym „code-driven” sposób, takie jak właściwości systemowych, zmiennych środowiskowych, właściwości projektu, itp
mkobit
1
Jak wspomniano w odpowiedzi stackoverflow.com/a/52484259/340175 , istnieje przydatny wpis na blogu blog.gradle.org/stop-rerunning-tests, który wyjaśnia, dlaczego takie podejście nie jest zalecane jako podejście ogólne. Zgadzam się jednak, że może to być przydatne i spełnia to, o co chodzi w pytaniu.
JulianHarty
Tak, to jest przestarzała odpowiedź, kiedy pisałem ten Gradle był w wersji 2.11 i właśnie zaczął być użyteczny, ale wciąż miał wiele szorstkich krawędzi, które są dziś wypolerowane.
František Hartman
1
Świetna odpowiedź!!! Przekazał ją za pomocą parametru: gradle test -Prerun-tests. Kod w build.gradle:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
AlikElzin-kilaka
17

To był ostatnio temat na blogu Gradle'a Przestań ponownie uruchamiać swoje testy . Autor przedstawia przykład korzystania outputs.upToDateWhen { false }i wyjaśnia, dlaczego jest źle:

To faktycznie nie wymusza powtórek

To, co prawdopodobnie chciał powiedzieć autor tego fragmentu, to „Zawsze powtarzaj moje testy”. Ale to nie jest to, co robi ten fragment. Będzie tylko oznaczać zadanie jako nieaktualne, zmuszając Gradle do ponownego utworzenia wyniku. Ale w tym rzecz, jeśli pamięć podręczna kompilacji jest włączona, Gradle nie musi uruchamiać zadania, aby odtworzyć dane wyjściowe. Znajdzie wpis w pamięci podręcznej i rozpakuje wynik do katalogu wyjściowego testu.

To samo dotyczy tego fragmentu:

test.dependsOn cleanTest

Gradle rozpakuje wyniki testu z pamięci podręcznej kompilacji po wyczyszczeniu danych wyjściowych, więc nic nie zostanie ponownie uruchomione. Krótko mówiąc, te fragmenty tworzą bardzo kosztowny brak działania.

Jeśli teraz myślisz „OK, dezaktywuję też pamięć podręczną”, powiem ci, dlaczego nie powinieneś.

Następnie autor wyjaśnia, dlaczego ponowne przeprowadzenie niektórych testów jest stratą czasu:

Zdecydowana większość testów powinna być deterministyczna, tj. Biorąc pod uwagę te same dane wejściowe, powinny one dawać ten sam wynik.

W kilku przypadkach, w których chcesz ponownie uruchomić testy, w których kod nie uległ zmianie, powinieneś zamodelować je jako dane wejściowe. Oto oba przykłady z wpisu na blogu, które pokazują dodawanie danych wejściowych, aby zadanie użyło ich podczas sprawdzania aktualności.

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

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

Polecam przeczytanie całego wpisu na blogu.

mkobit
źródło
8
Brzmi to świetnie w konkretnym przypadku użycia, o którym mówisz, ale piszę testy po wdrożeniu dla zewnętrznej usługi sieciowej na żywo i po prostu używam junit i gradle, aby to osiągnąć. Kod badany nie mieszka w repo, aw rzeczywistości nie ma żadnego „kodu aplikacji” bo ja rzeczywiście testuje system produkcyjny na żywo zamiast samego kodu. Dzięki za odpowiedź, to jest bardzo przydatne! Chciałem tylko zwrócić uwagę, że istnieją dodatkowe przypadki użycia, które wymagają ponownego uruchamiania testów za każdym razem, nawet jeśli żaden z gradle kodu nie wie, o czym się zmienia
Brandon
11

Oto rozwiązanie wykorzystujące plik „build.gradle”, na wypadek gdybyś nie chciał modyfikować wiersza poleceń:

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

A oto wynik. Zwróć uwagę na 2 zmiany w stosunku do poprzedniego wyniku:

1) Na wyjściu pojawi się nowe zadanie „cleanTest”.

2) „test” jest zawsze czyszczony (tj. Nigdy nie jest „AKTUALNY”), więc jest wykonywany za każdym razem:

$ 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
źródło
1
uruchomiony cleanTestwcześniej testnie uruchomi ponownie testów, czyści ich dane wyjściowe, ale zadanie testowe nadal będzie pobierać wyniki testów z pamięci podręcznej - patrz github.com/gradle/gradle/issues/9153
dan.m was user2321368
8

--rerun-tasks działa, ale jest nieefektywny, ponieważ odtwarza wszystkie zadania.

cleanTest samo w sobie może nie wystarczyć ze względu na bufor kompilacji.

więc najlepszym sposobem na osiągnięcie tego jest:

./gradlew --no-build-cache cleanTest test
masc3d
źródło
0

Ponadto konieczność dodawania --rerun-tasksjest naprawdę zbędna. Nigdy się nie dzieje. Utwórz --no-rerun-tasksi ustaw jako --rerun-tasksdomyślną kiedycleanTask

user1648995
źródło
-1

TL; DR

test.dependsOn cleanTest
Topera
źródło
2
Według stackoverflow.com/a/52484259/466862 to nie zadziała.
Mark Rotteveel
Cóż, dokumentacja gradle jest trochę zagmatwana ... Tutaj mówią, że cleanTest może być użyty do tego celu. docs.gradle.org/current/userguide/… . A także działa na moim komputerze (i gradle w wersji 4.10.3);)
Topera
-4

Myślę, że to ważne pytanie, biorąc pod uwagę, że w Gradle można uruchomić to polecenie test, a dzieje się tak, że nic się nie dzieje!

Ale kwestionowałbym potrzebę zrobienia tego, jak powiedział Jolta w swoim komentarzu: jeśli żaden kod się nie zmienił, to dlaczego musisz ponownie testować? Jeśli masz wątpliwości co do danych wejściowych innych firm, powiedziałbym, że musisz uwzględnić to w kodzie aplikacji. Jeśli obawiasz się, że Twój kod może być „niestabilny”, tj. Może przejść wszystkie testy za pierwszym razem, ale nie drugi (lub setny), czy nie musisz zastanawiać się, dlaczego masz te wątpliwości i je rozwiązywać?

Osobiście uważam, że jest to (bardzo drobna) wada projektowa w Gradle: jeśli wszystko jest całkowicie aktualne, zamiast pisać „BUDUJ SUKCES”, powinno być napisane „NIE ZMIENIAJ SIĘ OD OSTATNIEJ SUKCESOWEJ BUDOWY: NIC NIE ZROBIONO”.

mike gryzoń
źródło
3
„czy nie musisz się zastanawiać, dlaczego masz te wątpliwości i odpowiadać na nie?”: Tak, ale aby uzyskać dane do przemyślenia, chciałbym kilka razy przeprowadzić testy i zobaczyć, co się stanie. Czy to takie szalone?
mhsmith
1
@mikerodent Częściowo zgadzam się z twoim punktem. Istnieją „łatwe” przypadki, zazwyczaj proste testy jednostkowe typu whitebox, w których brak zmiany kodu nie oznacza nic do ponownego przetestowania. Pomyśl jednak o testach z zależnościami. „O tak, docker nie działał itp.” Są testy, w których to infrastruktura (i dev you) konfiguruje zależności (są one „dostarczane”), a nie kompilacja. W takich przypadkach zawsze chcę mieć możliwość ponownego uruchomienia.
dbalakirev
@dbalakirev Tak, przyszło mi to do głowy ... ale czy nie powinieneś być w stanie kpić z roli tych zależności, takich jak Docker ...? To znaczy, jeśli tego nie robisz, czy nie przechowujesz przyszłych problemów? Nie mówię, że jestem w 100% pewien, ale myślę, że mówię, że twoje testy powinny, w świecie bez wątpienia bardziej idealnym niż nasz, obejmować wszystkie podstawy.
mike gryzoń
Możesz udawać, że tak, z którym masz zależność (docker), że jeśli zawiedzie na tobie, oznacza to, że chcesz uruchomić ponownie, nawet jeśli kod się nie zmienił. Chciałbym podkreślić, że ta myśl nie dotyczy testów jednostkowych lub testów, w których 1. próbujesz unikać zależności 2. lub przynajmniej kpisz z nich za pomocą frameworka testowego, ale kiedy są one naprawdę „dostarczane”, jeśli chcesz.
dbalakirev
2
__ jeśli żaden kod się nie zmienił, dlaczego musisz ponownie przetestować? __ Czy słyszałeś o testach integracyjnych?
Bogdan Mart