How to abort a Pipeline build if JUnit tests fail

Issue

I have a Pipeline job that has multiple stages. I would like the build to abort after the “test” stage and not continue if there are test failures. I also want to ensure that the test results are correctly archived.

Environment

  • CloudBees Jenkins Enterprise
  • Pipeline plugin
  • JUnit Plugin
  • Maven

Resolution

You can use a try catch block to achieve this.

The below example will catch the exception thrown if JUnit tests fail, archive the JUnit test results and abort the build.

The

node {

    stage "checkout"

    git url: '...'

    stage "test"

    try {
        // Any maven phase that that triggers the test phase can be used here.
        sh 'mvn test -B'
    } catch(err) {
        step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml'])
        throw err
    }

    stage "deploy"

    echo "Im deploying now!"
}

This stops the “deploy” stage from executing in the event of failed tests.

Note that we purposely don’t use -Dmaven.test.failure.ignore verify in the maven command here (as per the docs[1]). This means that an exception will be thrown when there are failed tests, which we catch, call the JUnitResultArchiver step to archive the test results, then re-throw the exception to abort the build.

Note that by default JUnitResultArchiver will mark the build as UNSTABLE when there are failed tests. If you want to mark the build as FAILURE instead then change the catch block to:

...
catch(err) {
  step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml'])
  if (currentBuild.result == 'UNSTABLE')
    currentBuild.result = 'FAILURE'
  throw err
}

[1] See Recording Test Results and Artifacts for more.

Have more questions? Submit a request

3 Comments

  • 0
    Avatar
    Lionel Orellana

    I would actually like the build to remain UNSTABLE when tests fail. From what I've seen the build will be marked as FAILURE when you throw err even if you don't set the result explicitly. The question then becomes how to abort the pipeline leaving the result as UNSTABLE.   

     

     

  • 0
    Avatar
    Evgeny Zislis

    The way it is described in this article, test results archiver will only work when the command failed. Most probably this is not what you want, you want the archiver to always do its work - both for failed runs and for successful test runs.

    A better way would be something like this -

    try {
      // test stuff
    }
    catch(err) {
    // handle the exception; or ignore it
    } finally {
    step([$class: 'JUnitResultArchiver', testResults: '**/TEST-*.xml'])
    }

    Another option is to allow the exception to be raised, but still archive the test results before raising it:

    try {
      // test stuff; notice there is no '} catch(err) {'
    } finally {
    step([$class: 'JUnitResultArchiver', testResults: '**/TEST-*.xml']) }
    Edited by Evgeny Zislis
  • 1
    Avatar
    Philip Cheong

    @Lionel With the version 2.4 of Pipeline Nodes and Processes Plugin that supports additional ways of handling shell scripts, this code works pretty well for me...

    node ('master') {
    stage "build"
    // build without tests
    checkout scm
    sh './gradlew clean build -x test -x integTest'

    stage "unit test"
    // returnStatus: true here will ensure the build stays yellow
    // when test cases are failing
    sh (script: './gradlew test', returnStatus: true)
    step([$class: 'JUnitResultArchiver',
    testResults: '**/build/test-results/test/TEST-*.xml'])

    if (currentBuild.result == null) {
     // if unit tests have failed currentBuild will be 'UNSTABLE'
    // and we should not bother to run integration tests
    stage "integration test"
    sh (script: './gradlew integTest', returnStatus: true)
    step([$class: 'JUnitResultArchiver',
    testResults: '**/build/test-results/integTest/TEST-*.xml'])
    }
    }

     

    Edited by Philip Cheong
Please sign in to leave a comment.