Gradle: วิธีแสดงผลการทดสอบในคอนโซลแบบเรียลไทม์?


231

ฉันต้องการที่จะเห็นผลการทดสอบ (system.out / err, บันทึกข้อความจากการทดสอบส่วนประกอบ) ขณะที่พวกเขาทำงานในคอนโซลเดียวกับที่ฉันเรียกใช้:

gradle test

และอย่ารอจนกระทั่งการทดสอบเสร็จสิ้นเพื่อดูรายงานการทดสอบ (ที่สร้างขึ้นเฉพาะเมื่อการทดสอบเสร็จสิ้นดังนั้นฉันจึงไม่สามารถ "tail -f" ในขณะที่ทำการทดสอบ)

คำตอบ:


169

คุณสามารถรัน Gradle ด้วยระดับการบันทึกข้อมูลบนบรรทัดคำสั่ง มันจะแสดงผลการทดสอบแต่ละครั้งให้คุณทราบ ข้อเสียคือคุณจะได้รับผลผลิตมากขึ้นสำหรับงานอื่น ๆ ด้วย

gradle test -i

13
ด้วย 1.0-milestone 6 Gradle DSL ตอนนี้ให้คุณกำหนดค่าโดยตรงโดยใช้testLogging.showStandardStreams = trueภายในการtestปิด
Benjamin Muschko

4
สิ่งนี้ใช้ไม่ได้ในระดับ 1.11 ฉันได้รับผลลัพธ์การดีบักจำนวนมาก แต่ไม่ใช่ผลการทดสอบแต่ละรายการ
David Moles

44
นั่น-iจะทำให้เกิดกลุ่มของข่าวสารที่ไม่เกี่ยวข้องบนสถานี
Thuy Trinh

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

1
คุณสามารถใช้grepเพื่อกรองบรรทัดที่ไม่ต้องการหลายพันบรรทัด ดูstackoverflow.com/questions/3963708/…
Mr-IDE

172

นี่คือเวอร์ชั่นแฟนซีของฉัน:

ผลการทดสอบแฟนซี

import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent

tasks.withType(Test) {
    testLogging {
        // set options for log level LIFECYCLE
        events TestLogEvent.FAILED,
               TestLogEvent.PASSED,
               TestLogEvent.SKIPPED,
               TestLogEvent.STANDARD_OUT
        exceptionFormat TestExceptionFormat.FULL
        showExceptions true
        showCauses true
        showStackTraces true

        // set options for log level DEBUG and INFO
        debug {
            events TestLogEvent.STARTED,
                   TestLogEvent.FAILED,
                   TestLogEvent.PASSED,
                   TestLogEvent.SKIPPED,
                   TestLogEvent.STANDARD_ERROR,
                   TestLogEvent.STANDARD_OUT
            exceptionFormat TestExceptionFormat.FULL
        }
        info.events = debug.events
        info.exceptionFormat = debug.exceptionFormat

        afterSuite { desc, result ->
            if (!desc.parent) { // will match the outermost suite
                def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} passed, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped)"
                def startItem = '|  ', endItem = '  |'
                def repeatLength = startItem.length() + output.length() + endItem.length()
                println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength))
            }
        }
    }
}

13
ในความคิดของฉันนี่คือคำตอบที่ดีที่สุดที่นี่ มันมีชุดตัวเลือกที่ใหญ่ที่สุดและทุกคนสามารถกำหนดค่าการทดสอบตามที่ต้องการ
สลาฟ

2
@sealskej ฉันต้องคัดลอกรหัสนี้ไปที่ใดและจะเรียกใช้จากบรรทัดคำสั่งได้อย่างไร แก้ไข: เข้าใจแล้ว - เพียงแค่เพิ่มลงใน gradle.config ของโมดูลและทำงานตามปกติ
hardysim

ดี! ฉันเพิ่งลบท่อ|ออกจากstartItemเพราะการทำงานผ่าน Android Studio 2.2.3 จำได้ว่าเป็นข้อผิดพลาดในข้อความและมันก็สร้างความรำคาญในการสร้างความสำเร็จ
madlymad

1
และคุณเปิดใช้งานสีได้อย่างไร?
Durga Swaroop

1
@DurgaSwaroop ใช้งานได้นอกกรอบสำหรับฉัน โปรดตรวจสอบให้แน่ใจว่าแอปพลิเคชั่นเครื่องเทอร์มินัลของคุณรองรับสี ฉันใช้แอพ iTerm2 เป็นการส่วนตัว
Shubham Chaudhary

156

คุณสามารถเพิ่มการปิด Groovy ภายในไฟล์ build.gradle ของคุณซึ่งทำการบันทึกให้คุณ:

test {
    afterTest { desc, result -> 
        logger.quiet "Executing test ${desc.name} [${desc.className}] with result: ${result.resultType}"
    }
}

บนคอนโซลของคุณจากนั้นอ่านดังนี้:

:compileJava UP-TO-DATE
:compileGroovy
:processResources
:classes
:jar
:assemble
:compileTestJava
:compileTestGroovy
:processTestResources
:testClasses
:test
Executing test maturesShouldBeCharged11DollarsForDefaultMovie [movietickets.MovieTicketsTests] with result: SUCCESS
Executing test studentsShouldBeCharged8DollarsForDefaultMovie [movietickets.MovieTicketsTests] with result: SUCCESS
Executing test seniorsShouldBeCharged6DollarsForDefaultMovie [movietickets.MovieTicketsTests] with result: SUCCESS
Executing test childrenShouldBeCharged5DollarsAnd50CentForDefaultMovie [movietickets.MovieTicketsTests] with result: SUCCESS
:check
:build

ตั้งแต่รุ่น 1.1 Gradle สนับสนุนมากตัวเลือกมากขึ้นในการเข้าสู่ระบบการส่งออกการทดสอบ ด้วยตัวเลือกเหล่านั้นในมือคุณสามารถบรรลุผลลัพธ์ที่คล้ายกันด้วยการกำหนดค่าต่อไปนี้:

test {
    testLogging {
        events "passed", "skipped", "failed"
    }
}

4
สิ่งนี้จะสร้างผลลัพธ์หลังจากการทดสอบ สิ่งที่ฉันกำลังมองหาคือการดูลึกเข้าสู่ระบบ / รายงาน / system / printlns ฯลฯ .. การทดสอบกำลังทำงานอยู่ คิดเกี่ยวกับการดำเนินการทดสอบด้วย maven หรือเพียงแค่ใน IntelliJ / Eclipse: ผลผลิตที่เกิดขึ้นในเวลาจริง
tolitius

โอเคขออภัยที่เข้าใจผิดคำถามของคุณ สำหรับกรณีนี้คุณควรดูเอกสาร Gradle ต่อไปนี้: gradle.org/logging.html#sec:external_tools
stefanglase

1
แล้วฉันจะเปลี่ยนแปลงอะไรเพื่อดูผลลัพธ์ ฉันเห็นตัวรับฟังและสิ่งที่กำหนดเองเหล่านี้ทั้งหมดในเอกสารประกอบ แต่ฉันไม่รู้ว่าจะกำหนดค่านี้อย่างไร
jpswain

118

ในฐานะที่เป็นstefanglaseตอบ:

เพิ่มรหัสต่อไปนี้ของคุณbuild.gradle(ตั้งแต่รุ่น 1.1) ทำงานได้ดีสำหรับการส่งออกในการส่งผ่าน , ข้ามและล้มเหลวในการทดสอบ

test {
    testLogging {
        events "passed", "skipped", "failed", "standardOut", "standardError"
    }
}

สิ่งที่ผมอยากจะบอกว่านอกจากนี้ (ผมพบว่าปัญหานี้เป็นปัญหาสำหรับการเริ่มก) คือการที่gradle testคำสั่งดำเนินการทดสอบเพียงหนึ่งครั้งต่อการเปลี่ยนแปลง

ดังนั้นถ้าคุณใช้มันครั้งที่สองจะมีการส่งออกไม่เกี่ยวกับผลการทดสอบ คุณยังสามารถเห็นสิ่งนี้ในผลลัพธ์ของสิ่งปลูกสร้าง: ไล่ระดับแล้วพูดว่าUP-TO-DATEในการทดสอบ ดังนั้นจึงไม่ได้ดำเนินการในเวลาที่ n

สมาร์ทไล่ระดับ!

gradle cleanTest testหากคุณต้องการที่จะบังคับให้กรณีทดสอบการทำงานการใช้งาน

นี่เป็นเรื่องเล็กน้อย แต่ฉันหวังว่ามันจะช่วยมือใหม่บางคน

แก้ไข

ในฐานะที่เป็นsparc_spread ที่ระบุไว้ในความคิดเห็น:

หากคุณต้องการที่จะบังคับให้ gradle การทำงานเสมอทดสอบสด (ซึ่งอาจจะไม่เสมอเป็นความคิดที่ดี) คุณสามารถเพิ่มการoutputs.upToDateWhen {false} testLogging { [...] }อ่านต่อที่นี่

ความสงบ.


11
เฮ้แค่อยากให้คุณรู้ว่าฉันพบวิธีที่ไม่ต้องพูดgradle cleanTest testทุกครั้ง (เหมือน Gradle 1.12) เพิ่มoutputs.upToDateWhen {false}ไปยังtestLogging {...}และที่ควรทำเคล็ดลับ มันจะบังคับให้ Gradle ทำการทดสอบทุกครั้ง ฉันพบนี้ในฟอรั่ม Gradle, โพสต์โดย Dockter ตัวเอง หวังว่านี่จะช่วยได้
sparc_spread

ฉันจะรวมexceptionFormat "full"เพื่อรับรายละเอียดเกี่ยวกับสิ่งที่ล้มเหลวมีประโยชน์เมื่อคุณใช้ AssertJ หรือ lib ที่คล้ายกัน
Shairon Toledo

5
แทนที่จะเป็นเช่นนั้นcleanTestคุณสามารถใช้test --rerun-tasks
gavenkoa

2
@gavenkoa ฉันคิดว่า--rerun-tasksจะทำให้งานทั้งหมดของคุณรันใหม่ไม่ใช่แค่งานสำหรับการทดสอบ
ThomasW

2
จริงcleanTest testบนล่าสุด Android Studio และ gradle 3.3 ไม่ทำงานในด้านของฉัน แต่--rerun-tasksไม่หลอกลวง ไม่รู้ทำไม แต่การอ่านคำตอบนี้ช่วยแก้ไขอาการปวดหัวของฉันได้จริงซึ่งบันทึกการทดสอบ f ** king อยู่ที่ไหนหลังจากฉันเพิ่มทุกสิ่ง
Wingzero

111

ข้อจำกัดความรับผิดชอบ: ฉันเป็นผู้พัฒนาปลั๊กอินตัวบันทึกการทดสอบ Gradle

คุณสามารถใช้Gradle Test Logger Pluginเพื่อพิมพ์บันทึกที่สวยงามบนคอนโซล ปลั๊กอินใช้ค่าเริ่มต้นที่สมเหตุสมผลเพื่อตอบสนองผู้ใช้ส่วนใหญ่ด้วยการกำหนดค่าน้อยหรือไม่มีเลย แต่ยังมีชุดรูปแบบและตัวเลือกการกำหนดค่าจำนวนมากเพื่อให้เหมาะกับทุกคน

ตัวอย่าง

ธีมมาตรฐาน ชุดรูปแบบมาตรฐาน

ธีมมอคค่า ธีมมอคค่า

การใช้

plugins {
    id 'com.adarshr.test-logger' version '<version>'
}

ตรวจสอบให้แน่ใจว่าคุณได้รับเวอร์ชันล่าสุดจาก Gradle Centralเสมอ

องค์ประกอบ

คุณไม่ต้องการกำหนดค่าใด ๆ เลย อย่างไรก็ตามปลั๊กอินมีตัวเลือกน้อย สิ่งนี้สามารถทำได้ดังนี้ (แสดงค่าเริ่มต้น):

testlogger {
    // pick a theme - mocha, standard, plain, mocha-parallel, standard-parallel or plain-parallel
    theme 'standard'

    // set to false to disable detailed failure logs
    showExceptions true

    // set to false to hide stack traces
    showStackTraces true

    // set to true to remove any filtering applied to stack traces
    showFullStackTraces false

    // set to false to hide exception causes
    showCauses true

    // set threshold in milliseconds to highlight slow tests
    slowThreshold 2000

    // displays a breakdown of passes, failures and skips along with total duration
    showSummary true

    // set to true to see simple class names
    showSimpleNames false

    // set to false to hide passed tests
    showPassed true

    // set to false to hide skipped tests
    showSkipped true

    // set to false to hide failed tests
    showFailed true

    // enable to see standard out and error streams inline with the test results
    showStandardStreams false

    // set to false to hide passed standard out and error streams
    showPassedStandardStreams true

    // set to false to hide skipped standard out and error streams
    showSkippedStandardStreams true

    // set to false to hide failed standard out and error streams
    showFailedStandardStreams true
}

ฉันหวังว่าคุณจะสนุกกับการใช้มัน


3
ดี! มีสิ่งที่น่าอัศจรรย์เหมือนบทสรุปของการทดสอบแบบผ่าน / ไม่ผ่าน / การข้ามที่นำไปสู่
MarkHu

ฉันเพิ่งรวมปลั๊กอิน แต่ฉันไม่เห็นการทดสอบระยะเวลาดำเนินการเหมือนในคอมไพล์ของคุณสำหรับการทดสอบทุกอย่างในวงเล็บ (1.6s) จะเปิดใช้งานอย่างไร
dk7

@ dk7 โดยค่าเริ่มต้นเฉพาะการทดสอบที่ใช้เวลานานกว่า 1 วินาทีในการทำงานจะมีการพิมพ์ระยะเวลา ดูเอกสารประกอบสำหรับข้อมูลเพิ่มเติม หากคุณต้องการที่จะเห็นระยะเวลาทั้งหมดเพียงแค่ตั้งค่าไปslowThreshold 0
adarshr

1
@ HaroldL.Brown ใช่แล้ว :) ฉันแค่ทำอะไรบางอย่างเล็กน้อยในขณะนี้ แต่มันก็ยังมีชีวิตอยู่
adarshr

1
Yup @VadymTyemirov เหมือนกับgithub.com/radarsh/gradle-test-logger-plugin/issues/137เมื่อฉันบันทึกมัน document
adarshr

49

เพิ่มไปที่build.gradleเพื่อหยุดการไล่ระดับสีจากการกลืน stdout และ stderr

test {
    testLogging.showStandardStreams = true
}

เป็นเอกสารที่นี่


38

งาน 'ทดสอบ' ไม่ทำงานสำหรับปลั๊กอิน Android สำหรับปลั๊กอิน Android ใช้งานดังต่อไปนี้

// Test Logging
tasks.withType(Test) {
    testLogging {
        events "started", "passed", "skipped", "failed"
    }
}

ดูต่อไปนี้: https://stackoverflow.com/a/31665341/3521637


3
น่ากลัว FYI Future me - บันทึกสองนาทีของคุณโดยไม่วางไว้ใน android {} block
Shubham Chaudhary

18

ในฐานะที่เป็นตามขึ้นไปตอบที่ดี Shubham ของผมชอบที่จะแนะนำให้ใช้enumค่าแทนสตริง โปรดดูที่เป็นเอกสารของชั้น TestLogging

import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent

tasks.withType(Test) {
    testLogging {
        events TestLogEvent.FAILED,
               TestLogEvent.PASSED,
               TestLogEvent.SKIPPED,
               TestLogEvent.STANDARD_ERROR,
               TestLogEvent.STANDARD_OUT
        exceptionFormat TestExceptionFormat.FULL
        showCauses true
        showExceptions true
        showStackTraces true
    }
}

12

เวอร์ชั่นเรียบง่ายที่ฉันโปรดปรานตามคำตอบของ Shubham Chaudhary ป้อนคำอธิบายรูปภาพที่นี่

ใส่ไว้ในbuild.gradleไฟล์:

test {
    afterSuite { desc, result ->
    if (!desc.parent)
        println("${result.resultType} " +
            "(${result.testCount} tests, " +
            "${result.successfulTestCount} successes, " +
            "${result.failedTestCount} failures, " +
            "${result.skippedTestCount} skipped)")
    }
}

7

ใน Gradle โดยใช้ปลั๊กอิน Android:

gradle.projectsEvaluated {
    tasks.withType(Test) { task ->
        task.afterTest { desc, result ->
            println "Executing test ${desc.name} [${desc.className}] with result: ${result.resultType}"
        }
    }
}

จากนั้นผลลัพธ์จะเป็น:

การดำเนินการทดสอบ testConversionMinutes [org.example.app.test.DurationTest] พร้อมผลลัพธ์: SUCCESS


3

ผสานคำตอบที่ยอดเยี่ยมของ ShubhamและJJD ใช้ enum แทนสตริง

tasks.withType(Test) {
   testLogging {
       // set options for log level LIFECYCLE
       events TestLogEvent.PASSED,
            TestLogEvent.SKIPPED, TestLogEvent.FAILED, TestLogEvent.STANDARD_OUT
       showExceptions true
       exceptionFormat TestExceptionFormat.FULL
       showCauses true
       showStackTraces true

    // set options for log level DEBUG and INFO
       debug {
        events TestLogEvent.STARTED, TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED, TestLogEvent.STANDARD_OUT, TestLogEvent.STANDARD_ERROR
        exceptionFormat TestExceptionFormat.FULL
       }
       info.events = debug.events
       info.exceptionFormat = debug.exceptionFormat

       afterSuite { desc, result ->
           if (!desc.parent) { // will match the outermost suite
               def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
               def startItem = '|  ', endItem = '  |'
               def repeatLength = startItem.length() + output.length() + endItem.length()
               println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength))
           }
       }
   }
}

2
ฉันขอให้คุณเพิ่มบริบทเพิ่มเติมให้กับคำตอบของคุณ คำตอบแบบรหัสเท่านั้นหรือลิงก์อย่างเดียวนั้นยากที่จะเข้าใจ มันจะช่วยผู้ถามและผู้อ่านในอนาคตทั้งสองหากคุณสามารถเพิ่มข้อมูลเพิ่มเติมในโพสต์ของคุณ
RBT

2

ตามจากคำตอบของ Benjamin Muschko (19 มีนาคม 2554) คุณสามารถใช้-iธงพร้อมกับgrepเพื่อกรองบรรทัดที่ไม่ต้องการจำนวน 1,000 บรรทัด ตัวอย่าง:

Strong filter - แสดงเฉพาะชื่อและผลการทดสอบแต่ละหน่วยและสถานะการสร้างโดยรวม ข้อผิดพลาดในการตั้งค่าหรือข้อยกเว้นจะไม่ปรากฏขึ้น

./gradlew test -i | grep -E " > |BUILD"

Soft filter - แสดงชื่อและผลการทดสอบแต่ละหน่วยรวมถึงข้อผิดพลาดในการตั้งค่า / ข้อยกเว้น แต่มันจะรวมถึงข้อมูลที่ไม่เกี่ยวข้อง:

./gradlew test -i | grep -E -v "^Executing |^Creating |^Parsing |^Using |^Merging |^Download |^title=Compiling|^AAPT|^future=|^task=|:app:|V/InstrumentationResultParser:"

ซอฟต์ฟิลเตอร์, ไวยากรณ์ทางเลือก: (โทเค็นการค้นหาจะแบ่งออกเป็นแต่ละสตริง)

./gradlew test -i | grep -v -e "^Executing " -e "^Creating " -e "^Parsing " -e "^Using " -e "^Merging " -e "^Download " -e "^title=Compiling" -e "^AAPT" -e "^future=" -e "^task=" -e ":app:" -e "V/InstrumentationResultParser:"

คำอธิบายวิธีการทำงาน:เอาต์พุตของคำสั่งแรก./gradlew test -iถูกไพพ์ไปยังคำสั่งที่สองgrepซึ่งจะกรองบรรทัดที่ไม่ต้องการจำนวนมากออกตามนิพจน์ทั่วไป "-E"เปิดใช้งานโหมดการแสดงออกปกติและ"|"หมายถึง "หรือ" ชื่อหน่วยทดสอบและผลที่ได้รับอนุญาตให้แสดงการใช้และสถานะโดยรวมที่ได้รับอนุญาตด้วย" > " "BUILD"ในตัวกรองแบบอ่อน"-v"ค่าสถานะหมายถึง"ไม่ได้มี"และ"^"หมายถึง "จุดเริ่มต้นของบรรทัด" ดังนั้นจะตัดออกทุกบรรทัดที่ขึ้นต้นด้วย "Executing" หรือเริ่มด้วย "Creating" ฯลฯ


ตัวอย่างสำหรับการทดสอบหน่วยอุปกรณ์ Android, กับ gradle 5.1:

./gradlew connectedDebugAndroidTest --continue -i | grep -v -e \
"^Transforming " -e "^Skipping " -e "^Cache " -e "^Performance " -e "^Creating " -e \
"^Parsing " -e "^file " -e "ddms: " -e ":app:" -e "V/InstrumentationResultParser:"

ตัวอย่างสำหรับการทดสอบครอบคลุมหน่วย Jacoco ที่มี gradle 4.10:

./gradlew createDebugCoverageReport --continue -i | grep -E -v "^Executing |^Creating |^Parsing |^Using |^Merging |^Download |^title=Compiling|^AAPT|^future=|^task=|:app:|V/InstrumentationResultParser:"

0

หากคุณมีการbuild.gradle.ktsเขียนในKotlin DSLคุณสามารถพิมพ์ผลการทดสอบด้วย (ฉันกำลังพัฒนาโครงการหลายแพลตฟอร์ม kotlin โดยไม่ต้องใช้ปลั๊กอิน "java"):

tasks.withType<AbstractTestTask> {
    afterSuite(KotlinClosure2({ desc: TestDescriptor, result: TestResult ->
        if (desc.parent == null) { // will match the outermost suite
            println("Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)")
        }
    }))
}

0

เพียงเพิ่มการปิดต่อไปนี้ใน build.gradle ของคุณ เอาต์พุตจะถูกพิมพ์หลังจากการดำเนินการทดสอบทุกครั้ง

test{
    useJUnitPlatform()
    afterTest { desc, result ->
        def output = "Class name: ${desc.className}, Test name: ${desc.name},  (Test status: ${result.resultType})"
        println( '\n' + output)
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.