จะเรียกใช้การทดสอบ Gradle ได้อย่างไรเมื่อการทดสอบทั้งหมดเป็นข้อมูลล่าสุด


132

ฉันตั้งค่าสคริปต์เกรดของฉันแล้ว เมื่อฉันรันบิวด์ Gradle ทุกอย่างจะทำงานและรันการทดสอบ jUnit

หลังจากนั้นเมื่อฉันเรียกใช้การทดสอบ Gradle ฉันจะได้รับสิ่งต่อไปนี้:

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

เมื่อฉันดำเนินการgradle cleanแล้ว Gradle build ทำงานได้แน่นอน ... ฉันต้องการรีเซ็ตเฉพาะการทดสอบไม่ใช่สร้างทั้งโครงการ: ฉันจะทำอย่างไร


3
ดูเหมือนว่าไม่จำเป็นตามข้อมูลที่ระบุ หากไม่มีการเปลี่ยนแปลงรหัสแอปพลิเคชันหรือรหัสทดสอบเหตุใดคุณจึงต้องเรียกใช้การทดสอบอีกครั้ง
Jolta

10
@Jolta การทดสอบบางอย่างในรหัสของฉันเกี่ยวข้องกับอินพุตของบุคคลที่สามฉันกำลังดำเนินการทดสอบของฉันไม่เพียง แต่เพื่อให้แน่ใจว่าฉันไม่ได้ใส่ข้อผิดพลาดใด ๆ ในรหัสและเพื่อตรวจสอบว่ามีอะไรเปลี่ยนแปลงในอินพุตของบุคคลที่สามหรือไม่ ที่ฉันได้รับ
USer22999299

4
ขออภัยที่จู้จี้จุกจิก แต่ฉันไม่คิดว่านี่เป็นวิธีคิดที่ถูกต้องเกี่ยวกับเรื่องนี้: หากคุณมีอินพุตของบุคคลที่สามแบบแปรผันไม่ใช่วิธีที่ถูกต้องในการจัดการกับสิ่งนี้เพื่อเยาะเย้ยอินพุตเหล่านี้ในทางใดทางหนึ่ง? การทดสอบควรเกี่ยวกับการทดสอบโค้ดที่คุณกำลังเขียน คุณไม่ได้รับอันตรายอย่างชัดเจนจากการได้รับผลบวกปลอมหากคุณอาศัยข้อมูลจากบุคคลที่สามเป็นสิ่งที่ยอมรับไม่ได้? กลยุทธ์นี้ไม่ควรรองรับการป้อนปัญหาเป็นส่วนหนึ่งของรหัสแอปของคุณใช่หรือไม่
หนูไมค์

9
@mikerodent ลองทดสอบรหัสของคุณกับบริการออนไลน์ของบุคคลที่สาม คุณต้องการตรวจสอบการเปลี่ยนแปลงที่เป็นไปได้ใน API บริการเพื่อให้สามารถตอบสนองด้วยการปรับใช้ ASAP การทดสอบ CI เป็นวิธีที่ดีไม่ใช่หรือ? การใช้การจำลองจะบอกให้คุณทราบว่ารหัสของคุณเองไม่มีการถอยหลัง แต่การอ้างอิงยังคงมีการเปลี่ยนแปลง การใช้บริการจริงจะบ่งบอกว่าผลิตภัณฑ์ของคุณสามารถดำเนินการตามที่คาดหวังได้จริงในสภาพแวดล้อมปัจจุบัน
Elist

5
สิ่งนี้ใช้ได้เช่นกันจากมุมมองการทดสอบการรวมซึ่งจุดของการทดสอบคือการตรวจสอบความถูกต้องของการรวมโค้ดของคุณกับบิตของโค้ดอื่น ๆ ซึ่งไม่เหมาะสมที่จะล้อเลียนในการพึ่งพา
1800 ข้อมูล

คำตอบ:


172

ทางเลือกหนึ่งที่จะใช้--rerun-tasksธงในบรรทัดคำสั่ง สิ่งนี้จะเรียกใช้งานทดสอบทั้งหมดอีกครั้งและงานทั้งหมดที่ขึ้นอยู่กับ

หากคุณสนใจที่จะเรียกใช้การทดสอบใหม่เท่านั้นอีกทางเลือกหนึ่งคือการทำให้ gradle ทำความสะอาดผลการทดสอบก่อนที่จะดำเนินการทดสอบ ซึ่งสามารถทำได้โดยใช้cleanTestงาน

พื้นหลังบางอย่าง - ปลั๊กอิน Java กำหนดงานที่สะอาดสำหรับแต่ละงานอื่น ๆ ตามเอกสาร :

cleanTaskName - ลบไฟล์ที่สร้างโดยงานที่ระบุ cleanJar จะลบไฟล์ JAR ที่สร้างโดยงาน jar และ cleanTest จะลบผลการทดสอบที่สร้างโดยงานทดสอบ

ดังนั้นสิ่งที่คุณต้องมีเพื่อเรียกใช้การทดสอบของคุณอีกครั้งคือการรันcleanTestงานเช่น:
gradle cleanTest test


4
gradle cleanTest testไม่ทำการทดสอบซ้ำมันจะล้างผลลัพธ์ของมัน แต่testงานจะยังคงได้รับผลการทดสอบจากแคช - ดูที่github.com/gradle/gradle/issues/9153
dan.m คือ user2321368

3
ความเห็นข้างบนนี้ใช่เลย แต่ถ้าคุณใช้แล้วมันจะทำงานตามที่คาดไว้เช่น--no-build-cache gradle cleanTest test --no-build-cache
vRallev

53

ตัวเลือกอื่น ๆ คือเพิ่มสิ่งต่อไปนี้ใน build.gradle ของคุณ:

test.outputs.upToDateWhen {false}

1
ฉันใช้เทคนิคนี้สำหรับfuncTestงานที่ฉันสร้างขึ้นเพื่อเรียกใช้การทดสอบการทำงาน
pharsicle

5
นี่เป็นแนวทางที่ดีกว่าคำตอบที่ยอมรับเนื่องจากจะใช้กับงานที่ต้องการเท่านั้น upToDateWhenสามารถนำมาใช้ในการใด ๆ "รหัสที่ขับเคลื่อนด้วย" วิธีเช่นคุณสมบัติระบบตัวแปรสภาพแวดล้อมคุณสมบัติของโครงการและอื่น ๆ
mkobit

1
ดังที่คำตอบstackoverflow.com/a/52484259/340175กล่าวถึงมีบล็อกโพสต์ที่มีประโยชน์blog.gradle.org/stop-rerunning-testsซึ่งอธิบายว่าเหตุใดจึงไม่แนะนำให้ใช้วิธีนี้เป็นแนวทางทั่วไป อย่างไรก็ตามฉันยอมรับว่าอาจมีประโยชน์และบรรลุตามที่คำถามถาม
JulianHarty

ใช่นี่เป็นคำตอบที่ลงวันที่เมื่อฉันเขียน Gradle นี้เป็นเวอร์ชัน 2.11 และเพิ่งเริ่มใช้งานได้ แต่ยังมีขอบขรุขระมากมายซึ่งได้รับการขัดเงาในวันนี้
František Hartman

1
ตอบโจทย์มาก !!! ส่งผ่านโดยใช้พารามิเตอร์: gradle test -Prerun-tests. รหัสใน build.gradle:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
AlikElzin-kilaka

22

gradle test --rerun-tasks

ระบุว่าการเพิ่มประสิทธิภาพงานใด ๆ ถูกละเว้น

ที่มา: https://gradle.org/docs/current/userguide/gradle_command_line.html


4
ฉันคิดว่ามันจะเรียกใช้งานที่ต้องพึ่งพาทั้งหมดอีกครั้งเช่นกันซึ่งไม่ใช่พฤติกรรมที่ผู้ถามตั้งใจไว้
AlikElzin-kilaka

17

เมื่อเร็ว ๆ นี้นี่เป็นหัวข้อในบล็อกโพสต์ของ Gradle หยุดการเรียกใช้การทดสอบของคุณใหม่ ผู้เขียนแสดงให้เห็นตัวอย่างการใช้outputs.upToDateWhen { false }และอธิบายว่าทำไมมันเป็นความผิด:

นี่ไม่ได้บังคับให้รีรันจริง

สิ่งที่ผู้เขียนตัวอย่างข้อมูลนี้อาจต้องการพูดคือ“ ทำการทดสอบซ้ำเสมอ” นั่นไม่ใช่สิ่งที่ตัวอย่างนี้ทำ มันจะทำเครื่องหมายว่างานล้าสมัยเท่านั้นบังคับให้ Gradle สร้างเอาต์พุตขึ้นใหม่ แต่นี่คือสิ่งที่หากเปิดใช้งานบิวด์แคช Gradle ไม่จำเป็นต้องรันงานเพื่อสร้างเอาต์พุตใหม่ จะพบรายการในแคชและแตกผลลัพธ์ลงในไดเร็กทอรีเอาต์พุตของการทดสอบ

เช่นเดียวกับตัวอย่างข้อมูลนี้:

test.dependsOn cleanTest

Gradle จะแกะผลการทดสอบออกจากบิลด์แคชหลังจากล้างเอาต์พุตแล้วจึงไม่มีการรันซ้ำ ในระยะสั้นตัวอย่างเหล่านี้กำลังสร้าง no-op ที่มีราคาแพงมาก

หากตอนนี้คุณคิดว่า“ โอเคฉันจะปิดการใช้งานแคชด้วย” ให้ฉันบอกคุณว่าทำไมคุณไม่ควรทำ

จากนั้นผู้เขียนจะอธิบายต่อไปว่าทำไมการเรียกใช้การทดสอบบางอย่างใหม่จึงเสียเวลา:

การทดสอบส่วนใหญ่ของคุณควรกำหนดขึ้นกล่าวคือได้รับปัจจัยการผลิตเดียวกันซึ่งควรให้ผลลัพธ์เดียวกัน

ในบางกรณีที่คุณต้องการเรียกใช้การทดสอบอีกครั้งโดยที่โค้ดไม่ได้เปลี่ยนแปลงคุณควรจำลองเป็นอินพุต ต่อไปนี้เป็นตัวอย่างทั้งจากบล็อกโพสต์ที่แสดงการเพิ่มอินพุตเพื่อให้งานใช้ในระหว่างการตรวจสอบล่าสุด

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

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

ฉันขอแนะนำให้อ่านบล็อกโพสต์ทั้งหมด


8
สิ่งนี้ฟังดูดีสำหรับกรณีการใช้งานเฉพาะที่คุณกำลังพูดถึง แต่ฉันกำลังเขียนการทดสอบหลังการปรับใช้กับบริการเว็บภายนอกที่ใช้งานอยู่และเพิ่งจะใช้ junit และ gradle เพื่อทำสิ่งนี้ให้สำเร็จ ภายใต้รหัสการทดสอบไม่ได้อยู่ใน repo และในความเป็นจริงมีคือไม่มี 'รหัสโปรแกรม' เพราะฉันจริงการทดสอบระบบการผลิตที่มีชีวิตอยู่มากกว่ารหัสของตัวเอง ขอบคุณสำหรับคำตอบนี้มีประโยชน์มาก! แค่อยากจะชี้ให้เห็นว่ามีกรณีการใช้งานเพิ่มเติมที่ต้องเรียกใช้การทดสอบใหม่ทุกครั้งแม้ว่าจะไม่มีการเปลี่ยนรหัสใดก็ตาม
Brandon

11

นี่คือวิธีแก้ปัญหาโดยใช้ไฟล์ "build.gradle" ในกรณีที่คุณไม่ต้องการแก้ไขบรรทัดคำสั่งของคุณ:

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

และนี่คือผลลัพธ์ สังเกต 2 การเปลี่ยนแปลงจากผลลัพธ์ก่อนหน้าของคุณ:

1) งาน 'cleanTest' ใหม่ปรากฏขึ้นในผลลัพธ์

2) 'ทดสอบ' จะถูกล้างเสมอ (เช่นไม่ 'UP-TO-DATE') ดังนั้นจึงถูกดำเนินการทุกครั้ง:

$ 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
การรันcleanTestก่อนหน้าtestนี้จะไม่ทำการทดสอบซ้ำมันจะล้างผลลัพธ์ แต่งานทดสอบจะยังคงได้รับผลการทดสอบจากแคช - ดูที่ github.com/gradle/gradle/issues/9153
dan.m คือ user2321368

8

--rerun-tasks ใช้งานได้ แต่ไม่มีประสิทธิภาพเนื่องจากรันงานทั้งหมดซ้ำ

cleanTest ด้วยตัวมันเองอาจไม่เพียงพอเนื่องจากสร้างแคช

ดังนั้นวิธีที่ดีที่สุดในการทำให้สำเร็จคือ:

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

0

นอกจากนี้การต้องเพิ่ม--rerun-tasksนั้นซ้ำซ้อนจริงๆ ไม่เคยเกิดขึ้น สร้าง--no-rerun-tasksและ--rerun-tasksตั้งค่าเริ่มต้นเมื่อcleanTask


-1

TL; DR

test.dependsOn cleanTest

2
ตามstackoverflow.com/a/52484259/466862ที่ใช้ไม่ได้
Mark Rotteveel

เอกสาร gradle ค่อนข้างสับสน .... ที่นี่พวกเขาบอกว่า cleanTest สามารถใช้เพื่อจุดประสงค์นี้ได้ docs.gradle.org/current/userguide/… . และยังใช้งานได้กับเครื่องของฉัน (และ gradle เวอร์ชัน 4.10.3);)
Topera

-4

ฉันคิดว่านี่เป็นคำถามที่ถูกต้องเนื่องจาก Gradle สามารถเรียกใช้คำสั่งนี้ได้ใน Gradle testและสิ่งที่เกิดขึ้นคือไม่มีอะไรเกิดขึ้น!

แต่ฉันจะถามถึงความจำเป็นในการทำเช่นนี้ตามที่ Jolta กล่าวในความคิดเห็นของเขา: ถ้าไม่มีการเปลี่ยนแปลงรหัสทำไมคุณต้องทดสอบใหม่ หากคุณมีข้อสงสัยเกี่ยวกับการป้อนข้อมูลของบุคคลที่สามฉันบอกว่าคุณต้องตอบสนองสิ่งนี้ในรหัสแอปของคุณ หากคุณกังวลว่ารหัสของคุณอาจ "ไม่เป็นขุย" กล่าวคือสามารถผ่านการทดสอบทั้งหมดในครั้งแรก แต่ไม่ใช่ครั้งที่สอง (หรือครั้งที่ 100) คุณไม่จำเป็นต้องคิดว่าทำไมคุณถึงมีข้อสงสัยเหล่านี้และจัดการกับพวกเขาหรือไม่?

โดยส่วนตัวแล้วฉันคิดว่านี่เป็นข้อผิดพลาดในการออกแบบ (เล็กน้อยมาก) ใน Gradle: ถ้าทุกอย่างเป็นปัจจุบันทั้งหมดแทนที่จะไป "สร้างสำเร็จ" ควรพูดว่า "ไม่มีการเปลี่ยนแปลงตั้งแต่การสร้างที่ประสบความสำเร็จครั้งสุดท้าย: ไม่มีอะไรทำ"


3
"คุณไม่จำเป็นต้องคิดว่าทำไมคุณถึงมีข้อสงสัยและจัดการกับพวกเขา": ใช่ แต่เพื่อให้ได้ข้อมูลมาคิดฉันต้องการทำการทดสอบสองสามครั้งและดูว่าจะเกิดอะไรขึ้น บ้าขนาดนั้นเลยเหรอ
mhsmith

1
@mikerodent ฉันเห็นด้วยบางส่วนกับประเด็นของคุณ มีกรณีที่ "ง่าย" ซึ่งโดยทั่วไปแล้วจะเป็นการทดสอบหน่วยไวท์บ็อกซ์แบบง่าย ๆ โดยที่การเปลี่ยนโค้ดไม่ได้หมายความว่าจะไม่มีการทดสอบซ้ำจริงๆ ลองนึกถึงการทดสอบที่มีการอ้างอิง "โอ้ใช่นักเทียบท่าไม่ได้ทำงาน ฯลฯ " มีการทดสอบที่โครงสร้างพื้นฐาน (และใน dev คุณ) ที่ตั้งค่าการอ้างอิง (มีการ "จัดเตรียมไว้ให้") ไม่ใช่โครงสร้าง ในกรณีเหล่านี้ฉันต้องการให้รีรันได้เสมอ
dbalakirev

@dbalakirev ใช่สิ่งนี้เกิดขึ้นกับฉัน ... แต่คุณไม่ควรล้อเลียนบทบาทของการอ้างอิงเหล่านี้เช่น Docker ... ? ฉันหมายความว่าถ้าคุณไม่ทำอย่างนั้นคุณจะไม่เก็บปัญหาในอนาคตไว้ใช่หรือไม่? ฉันไม่ได้บอกว่าฉันแน่ใจ 100% แต่สิ่งที่ฉันคิดว่าฉันกำลังพูดคือการทดสอบของคุณควรจะครอบคลุมทุกฐานในโลกอย่างไม่ต้องสงสัย
หนูไมค์

คุณอาจเยาะเย้ยใช่ซึ่งคุณมีการพึ่งพา (นักเทียบท่า) ว่าหากล้มเหลวในตัวคุณหมายความว่าคุณต้องการรันใหม่แม้ว่ารหัสจะไม่เปลี่ยนแปลงก็ตาม ฉันต้องการเน้นย้ำความคิดนี้ไม่ได้มีไว้สำหรับการทดสอบหน่วยหรือการทดสอบที่ 1. คุณพยายามหลีกเลี่ยงการอ้างอิง 2. หรืออย่างน้อยก็ล้อเลียนโดยใช้กรอบการทดสอบ แต่เมื่อมีการ "ให้" จริงๆถ้าคุณต้องการ
dbalakirev

2
__ ถ้าไม่มีการเปลี่ยนแปลงรหัสทำไมคุณต้องทดสอบใหม่ __ คุณเคยได้ยินเกี่ยวกับการทดสอบการรวมหรือไม่?
Bogdan Mart
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.