Bagaimana cara menjalankan tes Gradle ketika semua tes UP-TO-DATE?

131

Saya sudah menyiapkan skrip nilai saya. Ketika saya menjalankan Gradle build, semuanya berfungsi dan ia menjalankan tes jUnit.

Setelah itu ketika saya menjalankan tes Gradle saya mendapatkan yang berikut:

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

Ketika saya melakukan gradle clean, maka Gradle build berfungsi, tentu saja ... Saya ingin dapat mereset hanya tes, bukan membangun keseluruhan proyek: bagaimana saya harus melakukan ini?

USer22999299
sumber
3
Ini tampaknya tidak perlu, berdasarkan informasi yang diberikan. Jika kode aplikasi atau kode tes tidak berubah, mengapa Anda perlu menjalankan kembali tes?
Jolta
10
@Jolta Beberapa tes dalam kode saya terkait pada input 3-pihak, saya menjalankan tes saya tidak hanya untuk memastikan saya tidak memasukkan bug di dalam kode, juga untuk memeriksa apakah ada perubahan pada input 3-pihak yang saya dapatkan
USer22999299
4
Maaf untuk menjadi pemilih, tetapi saya tidak berpikir ini adalah cara berpikir yang benar tentang hal ini: jika Anda memiliki input 3-pihak variabel bukankah cara yang benar untuk berurusan dengan ini untuk mengejek input ini dengan cara tertentu? Pengujian sebenarnya harus tentang pengujian kode yang Anda tulis. Bukankah Anda dalam bahaya yang cukup jelas untuk mendapatkan hasil positif palsu jika Anda mengandalkan input 3 pihak agar tidak dapat diterima? Tidakkah strateginya adalah untuk memenuhi input masalah sebagai bagian dari kode aplikasi Anda?
mike rodent
9
@mikerodent pertimbangkan untuk menguji kode Anda terhadap layanan online pihak ke-3. Anda ingin memantau kemungkinan perubahan dalam API layanan untuk dapat merespons dengan perbaikan yang dikerahkan ASAP. Bukankah CI menguji cara yang baik untuk melakukan itu? Menggunakan tiruan hanya akan memberi tahu Anda kode Anda sendiri tidak memiliki regresi, tetapi dependensi mungkin masih memiliki perubahan. menggunakan layanan nyata akan menunjukkan bahwa produk Anda benar-benar dapat melakukan operasi yang diharapkan di lingkungan saat ini.
Elist
5
Ini juga berlaku dari sudut pandang pengujian integrasi di mana titik pengujian adalah untuk memvalidasi integrasi kode Anda dengan bit kode lainnya, di mana tidak tepat untuk mengejek ketergantungan
1800 INFORMASI

Jawaban:

172

Salah satu opsi akan menggunakan --rerun-tasksbendera di baris perintah . Ini akan menjalankan kembali semua tugas tes dan semua tugas yang bergantung padanya.

Jika Anda hanya tertarik untuk menjalankan kembali tes, maka pilihan lain adalah membuat gradle membersihkan hasil tes sebelum menjalankan tes. Ini dapat dilakukan dengan menggunakan cleanTesttugas.

Beberapa latar belakang - plugin Java mendefinisikan tugas bersih untuk masing-masing tugas lainnya. Menurut dokumentasi :

cleanTaskName - Menghapus file yang dibuat oleh tugas yang ditentukan. cleanJar akan menghapus file JAR yang dibuat oleh tugas jar, dan cleanTest akan menghapus hasil tes yang dibuat oleh tugas tes.

Karena itu, yang Anda butuhkan untuk menjalankan kembali tes Anda adalah menjalankan cleanTesttugas, yaitu:
gradle cleanTest test

Amnon Shochot
sumber
3
gradle cleanTest testtidak menjalankan kembali tes, itu membersihkan output mereka, tetapi testtugas itu masih akan mendapatkan hasil tes dari cache - lihat github.com/gradle/gradle/issues/9153
dan.m adalah user2321368
3
Komentar di atas benar. Tetapi jika Anda menggunakan --no-build-cache, maka itu akan berfungsi seperti yang diharapkan, misalnya gradle cleanTest test --no-build-cache.
vRallev
51

Opsi lain adalah menambahkan berikut ini di build.gradle Anda:

test.outputs.upToDateWhen {false}
František Hartman
sumber
1
Saya menggunakan teknik ini untuk funcTesttugas yang saya buat untuk menjalankan tes fungsional.
pharsicle
4
Ini adalah pendekatan yang jauh lebih baik daripada jawaban yang diterima, karena hanya akan diterapkan pada tugas yang diinginkan. The upToDateWhendapat digunakan dengan cara "kode-driven" seperti sifat sistem, variabel lingkungan, proyek properti, dll
mkobit
1
Sebagai jawaban stackoverflow.com/a/52484259/340175 menyebutkan, ada posting blog yang bermanfaat blog.gradle.org/stop-rerunning-tests yang menjelaskan mengapa pendekatan ini tidak direkomendasikan sebagai pendekatan umum. Namun saya setuju bahwa itu mungkin berguna dan mencapai apa yang ditanyakan.
JulianHarty
Ya, ini adalah jawaban yang bertanggal, ketika saya menulis Gradle ini pada versi 2.11 dan baru mulai dapat digunakan, tetapi masih memiliki banyak tepi yang kasar, yang dipoles hari ini.
František Hartman
1
Jawaban yang bagus !!! Lulus menggunakan parameter: gradle test -Prerun-tests. Kode dalam build.gradle:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
AlikElzin-kilaka
17

Ini baru-baru ini menjadi topik di postingan blog Gradle, Berhenti mengulang tes Anda . The Penulis menunjukkan contoh menggunakan outputs.upToDateWhen { false }dan menjelaskan mengapa itu salah:

Ini sebenarnya tidak memaksa tayangan ulang

Apa yang mungkin ingin dikatakan oleh penulis cuplikan ini adalah "Selalu jalankan kembali tes saya". Tapi bukan itu yang dilakukan cuplikan ini. Itu hanya akan menandai tugas yang kedaluwarsa, memaksa Gradle untuk membuat ulang output. Tapi ada satu hal, jika build cache diaktifkan, Gradle tidak perlu menjalankan tugas untuk menciptakan kembali output. Ini akan menemukan entri dalam cache dan membongkar hasilnya ke direktori output tes.

Hal yang sama berlaku untuk cuplikan ini:

test.dependsOn cleanTest

Gradle akan membongkar hasil tes dari cache build setelah output telah dibersihkan, jadi tidak ada yang akan dijalankan kembali. Singkatnya, cuplikan ini menciptakan no-op yang sangat mahal.

Jika Anda sekarang berpikir "Oke, saya juga akan menonaktifkan cache", izinkan saya memberi tahu Anda alasannya.

Kemudian, penulis melanjutkan untuk menjelaskan mengapa menjalankan kembali beberapa tes adalah buang-buang waktu:

Sebagian besar pengujian Anda harus bersifat deterministik, yaitu dengan memberikan input yang sama, mereka harus menghasilkan hasil yang sama.

Dalam beberapa kasus di mana Anda ingin menjalankan kembali tes di mana kode tidak berubah, Anda harus memodelkannya sebagai input. Berikut adalah kedua contoh dari posting blog yang menunjukkan penambahan input sehingga tugas akan menggunakannya selama pemeriksaan terbaru.

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

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

Saya sarankan membaca seluruh posting blog.

mkobit
sumber
8
Ini kedengarannya hebat untuk use case khusus yang Anda bicarakan, tapi saya menulis tes pasca-penempatan terhadap layanan web eksternal langsung dan kebetulan menggunakan junit dan gradle untuk mencapai ini. Kode yang diuji tidak hidup di repo, dan sebenarnya ada adalah tidak ada 'aplikasi kode' karena aku benar-benar menguji sistem produksi yang hidup bukan kode itu sendiri. Terima kasih atas jawabannya, ini sangat berguna! Hanya ingin menunjukkan bahwa ada kasus penggunaan tambahan yang mengharuskan Anda mengulang tes setiap kali meskipun tidak ada kode gradle yang tahu sedang berubah
Brandon
11

Berikut ini solusi menggunakan file "build.gradle", jika Anda tidak ingin mengubah baris perintah Anda:

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

Dan inilah hasilnya. Perhatikan 2 perubahan dari output Anda sebelumnya:

1) Tugas 'cleanTest' baru muncul di output.

2) 'test' selalu dibersihkan (tidak pernah 'UP-TO-DATE') sehingga dieksekusi setiap kali:

$ 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
Biji Teal
sumber
1
berjalan cleanTestsebelum testtidak akan menjalankan kembali tes, itu membersihkan output mereka, tetapi tugas tes masih akan mendapatkan hasil tes dari cache - lihat github.com/gradle/gradle/issues/9153
dan.m adalah user2321368
8

--rerun-tasks berfungsi, tetapi tidak efisien karena menjalankan kembali semua tugas.

cleanTest dengan sendirinya mungkin tidak cukup karena membangun cache.

jadi, cara terbaik untuk mencapai ini adalah:

./gradlew --no-build-cache cleanTest test
masc3d
sumber
0

Juga, harus menambahkan --rerun-tasksbenar-benar berlebihan. Tidak pernah terjadi. Buat --no-rerun-tasksdan buat --rerun-tasksdefault saatcleanTask

pengguna1648995
sumber
-1

TL; DR

test.dependsOn cleanTest
Topera
sumber
2
Menurut stackoverflow.com/a/52484259/466862 itu tidak akan berfungsi.
Mark Rotteveel
Nah, dokumen gradle agak membingungkan .... Di sini mereka mengatakan bahwa cleanTest dapat digunakan untuk tujuan ini. docs.gradle.org/current/userguide/… . Dan juga, ini bekerja pada komputer saya (dan versi grader 4.10.3);)
Topera
-4

Saya pikir ini adalah pertanyaan yang valid mengingat bahwa memungkinkan Gradle menjalankan perintah ini test, dan yang terjadi adalah tidak ada yang terjadi!

Tetapi saya akan mempertanyakan perlunya melakukan ini, seperti yang dikatakan Jolta dalam komentarnya: jika tidak ada kode yang berubah mengapa Anda perlu menguji ulang? Jika Anda ragu tentang input pihak ketiga, saya katakan Anda harus memenuhi ini dalam kode aplikasi Anda. Jika Anda khawatir kode Anda mungkin "tidak stabil", yaitu dapat lulus semua tes pertama kali tetapi tidak yang kedua (atau yang ke-100), tidakkah Anda perlu memikirkan mengapa Anda memiliki keraguan ini, dan mengatasinya?

Secara pribadi saya pikir ini adalah kesalahan desain (sangat kecil) di Gradle: jika semuanya benar-benar mutakhir, daripada menggunakan "BUILD SUCCESSFUL", ia seharusnya mengatakan "TIDAK BERUBAH SEJAK TAHUN TERAKHIR SUKSES BUILD BUILD: NOTHING DONE".

mike rodent
sumber
3
"Anda tidak perlu memikirkan mengapa Anda memiliki keraguan ini, dan mengatasinya?": Ya, tetapi untuk mendapatkan data untuk dipikirkan, saya ingin menjalankan tes beberapa kali dan melihat apa yang terjadi. Apakah itu gila?
mhsmith
1
@mikerodent Saya setuju sebagian dengan poin Anda. Ada kasus "mudah", biasanya tes unit kotak putih sederhana, di mana tidak ada perubahan kode yang berarti tidak ada yang benar-benar untuk menguji ulang. Pikirkan tentang tes dengan dependensi. "Oh yeah, buruh pelabuhan tidak berlari, dll." Ada tes di mana infrastruktur (dan di dev Anda) yang mengatur dependensi (mereka "disediakan") dan bukan membangun. Dalam kasus ini saya selalu ingin dapat menjalankan kembali.
dbalakirev
@dbalakirev Ya, ini terpikir oleh saya ... tetapi tidakkah Anda dapat mempermainkan peran dependensi ini, seperti Docker ...? Maksud saya, jika Anda tidak melakukan itu, bukankah Anda menyimpan masalah di masa depan? Saya tidak mengatakan bahwa saya 100% yakin, tetapi apa yang saya pikir saya katakan adalah bahwa tes Anda harus, di dunia tidak diragukan lagi lebih ideal daripada kami, mencakup semua basis.
mike rodent
Anda dapat mengejek ya, yang dengannya Anda memiliki ketergantungan (buruh pelabuhan) bahwa jika gagal pada Anda itu berarti Anda ingin menjalankan kembali bahkan jika kode tidak berubah. Saya ingin menekankan pemikiran ini bukan untuk tes unit atau tes di mana 1. Anda mencoba untuk menghindari dependensi 2. atau setidaknya mengejek mereka menggunakan kerangka uji, tetapi ketika mereka benar-benar "disediakan" jika Anda mau.
dbalakirev
2
__ jika tidak ada kode yang berubah mengapa Anda perlu menguji ulang? __ Pernahkah Anda mendengar tentang tes integrasi?
Bogdan Mart