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.
