В groovy script в результате теста jenkins, как мы можем получить информацию о пропущенных тестах, чтобы показать, был ли тест ожидаемым Failure (пройден или не пройден) или пропущен?

Графический интерфейс результатов теста jenkins показывает пропущенные или ожидаемые тесты Fail как пропущенные. Представление отдельного теста для пропущенных тестов или тестов с ожидаемой неудачей показывает «Пропущенное сообщение» и «Стандартный вывод».

например «Пропущенное сообщение» может быть:

  • пользовательское сообщение о пропуске

        *  e.g. from python @unittest.skip("some reason") tag or 
        *  e.g. raise unittest.SkipTest("thing not found.")
    
  • "ожидаемый сбой теста"
  • "Тест с отметкой xfail неожиданно проходит"

Мы используем скрипт groovy для создания отчетов о тестировании. Мы хотели бы включить больше информации о пропущенных тестах, а не просто "пропущено". Как мы можем получить информацию о пропущенном тесте, как в «Пропущенном сообщении» в графическом интерфейсе?

API jenkins задокументирован здесь:

https://javadoc.jenkins.io/plugin/junit/hudson/tasks/junit/TestResult.html

Нет специального вызова для получения информации о пропущенных или ожидаемых непройденных тестах. Я надеюсь, что после некоторых экспериментов можно будет получить информацию об ожидаемых ошибках через этот API testResult. Начиная с этих вызовов API:

String  getErrorDetails()
If there was an error or a failure, this is the text from the message.

String  getErrorStackTrace()
If there was an error or a failure, this is the stack trace, or otherwise null.

String  getName()
Gets the name of this object.

String  getStderr()
The stderr of this test.

String  getStdout()
The stdout of this test.

TestResult  getTestResult()
Returns the top level test result data.

String  getTitle()
Gets the human readable title of this result object.

В графическом интерфейсе:

  • Обычный пройденный тест просто имеет «Стандартный вывод».
  • Обычный неудачный тест имеет «Сообщение об ошибке», «Стек стека» и «Стандартный вывод».
  • Пропущенные или ожидаемые тестыFail показывают «Пропущенное сообщение» и «Стандартный вывод».

Мы используем python unittest для вывода файлов результатов теста junit. Загрузка этого в jenkins с помощью плагина результатов теста junit.

Я пропустил что-то в API результатов теста jenkins, который дал бы больше информации об ожидаемом сбое или пропущенных тестах? Я надеюсь найти информацию путем экспериментов с использованием API. И задокументируйте это в ответе здесь.

Вот суть сценария groovy отчета о тестировании (используется в плагине jenkins Execute Groovy Script после того, как плагин результатов jUnit собрал результаты теста):

import hudson.model.*
def build = Thread.currentThread().executable
workspace = build.getEnvVars()["WORKSPACE"]
reportfilename = workspace + "/testreport.html"
rf = new File(reportfilename);


def testCount = "0"
def testPassed = "0"
def testFailed = "0"
def testSkipped = "0"
def buildDuration = "0"

def workspace = "unknown"
def buildName = "unknown"
def BUILD_STATUS = ""
def BUILD_URL = ""

def testResult = null
def testResult1 = null
def testResult2 = null
def testDuration = ""
def caseResult = null

def buildNumber = 0
def buildNumHash = ""
def buildTimeString = ""
def rooturl = ""

try {
    buildNumber = build.number
    buildNumHash = build.getDisplayName()
    //currentBuildNumber = manager.build.number

    buildTimeString = build.getTime().format("YYYY-MMM-dd HH:mm:ss")

    if(build.testResultAction) {
        testResult = build.testResultAction
        testCount = String.format("%d",(testResult.totalCount))
        testPassed = String.format("%d",(testResult.result.passCount))
        testFailed = String.format("%d",(testResult.result.failCount))
        testSkipped = String.format("%d",(testResult.result.skipCount))
        testDuration = String.format("%.2f",(testResult.result.duration ))
    }

    workspace = build.getEnvVars()["WORKSPACE"]
    buildName = build.getEnvVars()["JOB_NAME"]
    BUILD_STATUS = build.getEnvVars()["BUILD_STATUS"]
    BUILD_URL = build.getEnvVars()["BUILD_URL"]

    testResult1 = hudson.tasks.junit.TestResult 
    testResult2 = build.getAction(hudson.tasks.junit.TestResultAction.class)
    caseResult = hudson.tasks.junit.CaseResult

    rooturl = manager.hudson.rootUrl

} catch(Exception ex) {
    rf << "exception accessing build.testResultAction object.";
    //rf << ex;
}

// in groovy the write RE-creates the file, rf << "whatever" is used to append.
rf.write "<html><head><title>testreport.groovy #$buildNumber $buildName</title></head><body>"

rf << "Summary test report <br><br>\n\
<b>TEST RESULT:</b> $testCount total, <b>$testPassed pass</b>, <b>$testFailed fail</b>, $testSkipped skip.<br>\n\
Workspace : $workspace<br>\n\
Project Name : $buildName $buildNumHash<br><br>\n\
"

if (build) {

    rf << """<!-- GENERAL INFO -->\n\
\n\
<TABLE>\n\
  <TR><TD align=\"right\">\n\
    <j:choose>\n\
      <j:when test=\"${build.result=='SUCCESS'}\">\n\
        <IMG SRC=\"${rooturl}static/e59dfe28/images/32x32/blue.gif\" />\n\
      </j:when>\n\
      <j:when test=\"${build.result=='FAILURE'}\">\n\
        <IMG SRC=\"${rooturl}static/e59dfe28/images/32x32/red.gif\" />\n\
      </j:when>\n\
      <j:otherwise>\n\
        <IMG SRC=\"${rooturl}static/e59dfe28/images/32x32/yellow.gif\" />\n\
      </j:otherwise>\n\
    </j:choose>\n\
  </TD><TD valign='center'><B style='font-size: 200%;'>BUILD ${build.result}</B></TD></TR>\n\
  <TR><TD>Build URL</TD><TD><A href=\"${rooturl}${build.url}\">${rooturl}${build.url}</A></TD></TR>\n\
  <TR><TD>Project:</TD><TD>${buildName}</TD></TR>\n\
  <TR><TD>Date of build:</TD><TD>${buildTimeString}</TD></TR>\n\
  <TR><TD>Build duration:</TD><TD>${build.durationString}</TD></TR>\n\
  <TR><TD>Test duration:</TD><TD>${testDuration}</TD></TR>\n\
</TABLE>\n\
<BR/>\n\
"""
}

if(!testResult) {
    rf << "<br>No test result<br>"
    rf << "</body></html>"
    return ("No test result")
}

def junitResultList = [];
junitResultList.add(testResult.getResult())
if (junitResultList.size() > 0) {
    rf << "<br>test result from build.testResultAction"
} else {
    junitResultList.add(testResult2.getResult())
    if (junitResultList.size() > 0) {
        rf << "<br>test result from build.getAction"
    } else {
        rf << "<br>No results in 'testResult2'<br>\n"
        junitResultList.add(testResult1.getResult())
    }
}
//rf << "<br>DEBUG" + junitResultList.size() + " test items"
// API: http://hudson-ci.org/javadoc/hudson/tasks/junit/PackageResult.html

rf << "<!-- JUnit TEMPLATE: all tests PASS FAIL SKIP -->\n"
if (junitResultList.size() > 0) { 
    rf << '<TABLE width="100%">\n'
    rf << "<TR><TD class='bg1' colspan='2'><B>${junitResultList.first().displayName}</B></TD></TR>\n"
    junitResultList.each { junitResult -> 
        junitResult.getChildren().each { packageResult -> 
            rf << "<TR><TD class='bg2' colspan='2'> <B>TEST SUITE: ${packageResult.getName()} Failed: ${packageResult.getFailCount()} test(s), Passed: ${packageResult.getPassCount()} test(s)</B>, Skipped: ${packageResult.getSkipCount()} test(s), Total: ${packageResult.getPassCount()+packageResult.getFailCount()+packageResult.getSkipCount()} test(s)</TD></TR>\n"
            packageResult.getChildren().each { suite -> 
                suite.getChildren().each { test ->
                    def colour = "lightgreen"
                    def highlight1=""
                    def highlight2=""
                    RESULT = test.getStatus().name() // FAILED or PASSED or SKIPPED (.name() not .value)
                    // hudson.tasks.junit.CaseResult.Status.FAILED
                    if (RESULT == "FAILED" || RESULT == "REGRESSION") {
                        colour = "#ffcccc" 
                        highlight1="<B>"
                        highlight2="</B>"
                    }
                    if (RESULT == "SKIPPED") { colour = "#ffffb3" }

                    rf << "<TR bgcolor='${colour}'><TD class='test' colspan='2'>${highlight1}<li>${RESULT}: ${test.getFullName()} </li>${highlight2}</TD></TR>\n"
                } 
            }
        }
    } 
    rf << '</TABLE><BR/>\n'
}

rf << "testreport.groovy</body></html>\n"



person gaoithe    schedule 07.01.2020    source источник


Ответы (1)


Я нашел это! Ответ заключается в вызове недокументированного метода test.getSkippedMessage(). Он виден в исходном коде.

py.test записывает сообщение о пропуске в junit xml. Отметьте так внутри результата теста: <skipped message="the skipped message">

Это сообщение может быть настраиваемым сообщением из сообщения в вызове skip(), или в случае xfail или xpass сообщение устанавливается pytest на «ожидаемый сбой теста» или «непредвиденное прохождение теста с отметкой xfail».

Плагин jenkins junit читает файл junit xml. Сообщение доступно через API здесь: class CaseResult getSkippedMessage() см. https://github.com/jenkinsci/junit-plugin/blob/master/src/main/java/hudson/tasks/junit/CaseResult.java Хотя это здесь не задокументировано: http://hudson-ci.org/javadoc/hudson/tasks/junit/CaseResult.html

Измените эту часть кода выше:

                    if (RESULT == "SKIPPED") { colour = "#ffffb3" }

to:

                    def moremessage1 = "";

.
.
.

                    if (RESULT == "SKIPPED") { 
                        colour = "#ffffb3" 
                        moremessage1 += "<br>test.getSkippedMessage():" + test.getSkippedMessage() + "</br>"
                    }

                    rf << "<TR bgcolor='${colour}'><TD class='test' colspan='2'>${highlight1}<li>${RESULT}: ${test.getFullName()} ${moremessage1}</li>${highlight2}</TD></TR>\n"

больше тестового кода, полезного при экспериментировании с этим API:

                    if (RESULT == "SKIPPED") { 
                        colour = "#ffffb3" 
                        moremessage1 += "<br>test.getSkippedMessage():" + test.getSkippedMessage() + "</br>"
                        moremessage1 += "<br>test.getStatus().getMessage():" + test.getStatus().getMessage() + "</br>"
                        moremessage1 += "<br>test.getTitle():" + test.getTitle() + "</br>"
                        moremessage1 += "<br>test.getStdout():" + test.getStdout() + "</br>"
                        moremessage1 += "<br>test.getStderr():" + test.getStderr() + "</br>"
                        moremessage1 += "<br>test.getErrorDetails():" + test.getErrorDetails() + "</br>"
                        moremessage1 += "<br>test.getErrorStackTrace():" + test.getErrorStackTrace() + "</br>"
                        moremessage1 += "<br>test.getName():" + test.getName() + "</br>"
                        moremessage1 += "<br>test.getSafeName():" + test.getSafeName() + "</br>"
                        moremessage1 += "<br>test.getSimpleName():" + test.getSimpleName() + "</br>"
                        moremessage1 += "<br>test.getFullName():" + test.getFullName() + "</br>"
                        moremessage1 += "<br>test.getClassName():" + test.getClassName() + "</br>"
                        moremessage1 += "<br>test.getDisplayName():" + test.getDisplayName() + "</br>"
                        moremessage1 += "<br>test.getPackageName():" + test.getPackageName() + "</br>"
person gaoithe    schedule 09.01.2020