Jenkins Testing and Code Quality Integration

A CI pipeline without testing is just an automated build. Testing and code quality tools are what give the team confidence that new code does not break existing functionality or introduce technical debt.

Jenkins connects to testing frameworks, code coverage tools, and static analysis tools. It collects their reports, displays trends, and can fail builds when quality drops below your defined thresholds.

Types of Tests in a CI Pipeline

CI Test Pyramid:
                     /\
                    /  \
                   /    \
                  / E2E  \           End-to-end tests
                 /  Tests \         (slowest, fewest)
                /----------\
               /            \
              / Integration  \     Integration tests
             /    Tests       \    (medium speed)
            /------------------\
           /                    \
          /    Unit Tests        \  Unit tests
         /                        \ (fastest, most)
        /--------------------------\

Jenkins runs all three layers.
Unit tests run on every commit.
Integration tests run on feature branch merges.
E2E tests run before production deployment.

Publishing JUnit Test Results

Most testing frameworks (JUnit, TestNG, pytest, Jest, Mocha) produce XML reports in JUnit format. Jenkins reads these XML files and displays results in the build page with pass/fail counts and trends.

pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                sh 'mvn test'
            }
            post {
                always {
                    // Publish test results whether tests pass or fail
                    junit 'target/surefire-reports/*.xml'
                }
            }
        }
    }
}
Jenkins test result display:

  Build #45 — Test Results
  ┌─────────────────────────────────────────┐
  │  Tests: 127  Failures: 2  Skipped: 4    │
  │                                         │
  │  Failed Tests:                          │
  │    ✗ UserServiceTest.testLogin          │
  │      Expected: 200  Actual: 401         │
  │    ✗ OrderServiceTest.testCheckout      │
  │      NullPointerException at line 87    │
  │                                         │
  │  Test Duration: 3m 42s                  │
  └─────────────────────────────────────────┘

  Test Trend Graph (last 10 builds):
  Build:  #36  #37  #38  #39  #40  #41  #42  #43  #44  #45
  Pass:   125  127  127  127  127  127  127  127  127  125
  Fail:     0    0    0    0    0    0    0    0    0    2

Code Coverage with JaCoCo

Code coverage measures what percentage of your code is executed by tests. JaCoCo is the most popular coverage tool for Java projects.

Pipeline with JaCoCo coverage:

  stage('Test with Coverage') {
      steps {
          sh 'mvn clean test jacoco:report'
      }
      post {
          always {
              junit 'target/surefire-reports/*.xml'

              // Publish JaCoCo HTML report
              publishHTML([
                  allowMissing: false,
                  alwaysLinkToLastBuild: true,
                  keepAll: true,
                  reportDir: 'target/site/jacoco',
                  reportFiles: 'index.html',
                  reportName: 'Code Coverage Report'
              ])
          }
      }
  }
Coverage Report Example:

  Class                    Line Coverage   Branch Coverage
  UserService.java         94%             87%
  OrderService.java        78%             61%   ← below threshold
  PaymentService.java      91%             83%
  Overall                  88%             77%

Minimum thresholds set in pipeline:
  Line coverage:    80% minimum → PASS
  Branch coverage:  70% minimum → PASS

Failing Builds on Coverage Drop

Set minimum coverage thresholds so the build fails if coverage drops too low. This prevents developers from adding code without writing tests for it.

// Using JaCoCo plugin
stage('Coverage Check') {
    steps {
        jacoco(
            execPattern: 'target/jacoco.exec',
            classPattern: 'target/classes',
            sourcePattern: 'src/main/java',
            minimumLineCoverage: '80',
            minimumBranchCoverage: '70',
            changeBuildStatus: true   // FAIL build if below thresholds
        )
    }
}

Static Code Analysis with SonarQube

SonarQube analyzes your code for bugs, security vulnerabilities, and code smells — issues that do not cause test failures but make the code harder to maintain or potentially unsafe.

SonarQube Categories:

  Bugs:
    Code that will likely behave incorrectly at runtime
    Example: Null pointer dereference, resource leak

  Vulnerabilities:
    Security weaknesses attackers could exploit
    Example: SQL injection risk, hardcoded password

  Code Smells:
    Code that is confusing, duplicated, or overly complex
    Example: Method with 200 lines, copy-pasted code blocks

  Security Hotspots:
    Code areas that need manual review for security
    Example: Use of MD5 hashing, HTTP instead of HTTPS
SonarQube pipeline integration:

  pipeline {
      agent any

      environment {
          SONAR_TOKEN = credentials('sonarqube-token')
      }

      stages {
          stage('SonarQube Analysis') {
              steps {
                  withSonarQubeEnv('SonarQube-Server') {
                      sh '''
                        mvn sonar:sonar \
                          -Dsonar.projectKey=myapp \
                          -Dsonar.projectName="My Application" \
                          -Dsonar.host.url=http://sonar.mycompany.com \
                          -Dsonar.login=${SONAR_TOKEN}
                      '''
                  }
              }
          }

          stage('Quality Gate') {
              steps {
                  // Pause and wait for SonarQube to finish analysis
                  timeout(time: 5, unit: 'MINUTES') {
                      waitForQualityGate abortPipeline: true
                      // abortPipeline: true → FAIL build if quality gate fails
                  }
              }
          }
      }
  }
SonarQube Quality Gate result:

  Quality Gate: PASSED ✓
    Reliability: A (0 new bugs)
    Security:    A (0 new vulnerabilities)
    Maintainability: A (0 new code smells)
    Coverage:    83.2% (threshold: 80%)
    Duplications: 2.1% (threshold: 3%)

  Quality Gate: FAILED ✗
    Coverage: 71.4% → below 80% threshold
    → Build marked as FAILURE
    → Developer must add tests before merging

Checkstyle and Code Formatting

Checkstyle enforces code formatting and style rules in Java projects. Teams define a set of rules (line length, naming conventions, import order) and the build fails when code breaks those rules.

stage('Style Check') {
    steps {
        sh 'mvn checkstyle:check'
    }
    post {
        always {
            recordIssues(
                tools: [checkStyle(pattern: 'target/checkstyle-result.xml')],
                qualityGates: [[threshold: 0, type: 'NEW', unstable: false]]
            )
        }
    }
}

Running Tests for Node.js Projects

pipeline {
    agent { docker { image 'node:20-alpine' } }

    stages {
        stage('Install') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Lint') {
            steps {
                sh 'npm run lint'
            }
        }

        stage('Unit Tests') {
            steps {
                sh 'npm test -- --ci --testResultsProcessor jest-junit'
            }
            post {
                always {
                    junit 'jest-results/junit.xml'
                }
            }
        }

        stage('Coverage') {
            steps {
                sh 'npm test -- --coverage --ci'
            }
            post {
                always {
                    publishHTML([
                        reportDir: 'coverage/lcov-report',
                        reportFiles: 'index.html',
                        reportName: 'Coverage Report'
                    ])
                }
            }
        }
    }
}

Test Reports in Blue Ocean

Blue Ocean (a Jenkins UI plugin) shows test results visually in the pipeline view. Failed tests appear highlighted in red directly in the stage where they failed, making it fast to identify which stage caused the problem and which tests failed.

Blue Ocean pipeline view:

  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
  │ Checkout │→ │  Build   │→ │  Tests   │→ │  Deploy  │
  │   ✓ 8s   │  │  ✓ 45s   │  │ ✗ 3m12s │   │ SKIPPED  │
  └──────────┘  └──────────┘  └──────────┘  └──────────┘
                                    │
                                    ↓
                         Failed Tests (2):
                         • UserServiceTest.testLogin
                         • OrderServiceTest.testCheckout

Key Points

  • Publish JUnit XML reports using the junit step — Jenkins shows trends over multiple builds.
  • Code coverage tools like JaCoCo measure what percentage of code is covered by tests.
  • Set minimum coverage thresholds to fail builds when developers add untested code.
  • SonarQube finds bugs, vulnerabilities, and code smells and blocks merges through Quality Gates.
  • Checkstyle enforces code style rules and can fail builds when formatting standards are violated.

Leave a Comment