【问题标题】:In groovy script in jenkins test result how can we get information on skipped tests to show if test was expectedFailure(pass or fail) or Skipped?在 jenkins 测试结果中的 groovy 脚本中,我们如何获取有关跳过测试的信息以显示测试是预期失败(通过或失败)还是跳过?
【发布时间】:2020-01-07 15:26:56
【问题描述】:

jenkins 测试结果 GUI 将 skipped 或 expectedFail 测试显示为已跳过。 跳过或预期失败测试的单独测试视图显示“跳过消息”和“标准输出”

例如“跳过的消息”可以是:

  • 自定义跳过消息

        *  e.g. from python @unittest.skip("some reason") tag or 
        *  e.g. raise unittest.SkipTest("thing not found.")
    
  • “预期测试失败”
  • “xfail-marked 测试意外通过”

我们正在使用 groovy 脚本生成测试报告。 我们希望包含更多关于跳过测试的信息,而不仅仅是“跳过”。 我们如何在 GUI 视图中的“已跳过消息”中获取有关已跳过测试的信息?

jenkins API 记录在这里:

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

没有具体要求获取有关已跳过或预期失败测试的信息。 我希望通过一些实验,可以通过这个 testResult API 获得 expectedFail 信息。 从这些 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.

在图形用户界面中:

  • 正常通过的测试只有“标准输出”。
  • 正常失败的测试有“错误消息”、“堆栈跟踪”和“标准输出”。
  • 跳过或预期失败测试显示“跳过消息”和“标准输出”。

我们正在使用 python unittest 输出 junit 测试结果文件。 使用 junit 测试结果插件将其加载到 jenkins 中。

我是否错过了 jenkins 测试结果 API 中的某些内容,这些内容可以提供有关预期失败或跳过测试的更多信息? 我希望通过使用 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"


【问题讨论】:

    标签: jenkins groovy junit test-reporting


    【解决方案1】:

    我找到了! 答案是调用未记录的 test.getSkippedMessage() 方法。在源代码中可见。

    py.test 将跳过消息写入 junit xml。 在测试结果中这样标记:&lt;skipped message="the skipped message"&gt;

    该消息可以是来自 skip() 调用中消息的自定义消息,或者在 xfail 或 xpass 的情况下,消息由 pytest 设置为“预期测试失败”或“xfail 标记的测试意外通过”。

    jenkins junit 插件读取 junit xml。 该消息可通过此处的 API 获得: 类 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" }
    

    到:

                        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>"
    

    【讨论】:

      猜你喜欢
      • 2020-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-15
      相关资源
      最近更新 更多