Continuous Integration & Deployment Automation

Continuous Integration & Deployment Automation

Java Automation Testing – From Beginner to Advanced

Goal:
Build a fully‑automated CI/CD pipeline that compiles, tests, deploys, runs smoke tests, and generates quality reports for a Java web application.

Audience:
1️⃣ Beginners – want to understand the core concepts and get a simple pipeline running.
2️⃣ Intermediate – need a working implementation that can be extended.
3️⃣ Advanced – want optimisations, best‑practice patterns, and real‑world insights.

Prerequisites – Java 21+, Maven/Gradle, Git, Docker (optional), Kubernetes (optional), Selenium 4.x, JUnit5 or TestNG, Jenkins 2.440+.


Table of Contents

SectionTopics
1. FundamentalsCI/CD concepts, Jenkins basics, pipeline syntax, test automation, deployment, smoke tests, reporting
2. ImplementationJenkins setup, Jenkinsfile, Maven/Gradle build, Selenium tests, Docker/K8s deployment, smoke tests, reporting
3. Advanced TopicsPipeline as code best practices, parallel/distributed tests, Docker‑in‑pipeline, canary/blue‑green, caching, shared libs
4. Real‑World ApplicationsE‑commerce, banking, microservices, continuous delivery, regression suites
5. ExercisesStep‑by‑step projects, code challenges, optimisation tasks

All code snippets are in Java (or Groovy for Jenkins) and are fully commented.


1. Fundamentals

1.1 Continuous Integration & Continuous Deployment

ConceptWhat it meansWhy it matters
CIDevelopers merge code into a shared repo frequently (at least once a day). The CI server automatically builds and runs tests.Detects integration bugs early.
CDAfter a successful build, the code is automatically deployed to an environment (staging/production).Reduces manual deployment errors and speeds time‑to‑market.
PipelineA scripted definition of the CI/CD steps – usually in a Jenkinsfile.Keeps the pipeline versioned with the code.

Industry Insight – Most Fortune‑500 companies run their pipelines in Jenkinsfile format (Declarative or Scripted). It’s the single source of truth for the build process.

1.2 Jenkins Basics

  • Master – The Jenkins server that orchestrates jobs.
  • Agent – A worker node that executes the pipeline stages.
  • Credentials – Securely store tokens, SSH keys, etc. Use Jenkins Credentials Plugin.

Jenkinsfile Syntax

pipeline {
    agent any
    environment {
        MAVEN_HOME = '/opt/maven'
    }
    stages {
        stage('Checkout') { steps { checkout scm } }
        stage('Build')   { steps { sh 'mvn clean package' } }
        stage('Test')    { steps { sh 'mvn test' } }
    }
}

Tip: Use agent any for small projects, but for heavy workloads, specify a dedicated agent (label 'docker').

1.3 Test Automation Overview

  • Selenium – Browser automation.
  • TestNG/JUnit5 – Test frameworks.
  • Page Object Model – Encapsulate page interactions.

Professional Insight – Keep test code in a separate module (src/test/java). This keeps the production code clean and allows you to run tests in isolation.

1.4 Deployment Basics

TargetToolTypical Command
Tomcatmvn tomcat7:deployDeploy WAR
Dockerdocker build && docker pushBuild & push image
Kuberneteskubectl applyApply manifest

Edge Case – When deploying to a shared staging environment, you must use unique tags or namespace to avoid collisions.

1.5 Smoke Tests

  • Quick sanity checks after deployment:
    • Verify the application is reachable (curl -I http://app).
    • Basic functional flows (login, checkout).
  • Run them in a separate pipeline stage.

1.6 Test Reporting

ToolOutputIntegration
AllureHTML reportsallure serve
ExtentReportsRich UIMaven plugin
JUnit XMLJenkins built‑inpublishJUnitResults

Pro Tip – Store the reports as artifacts and archive them in Jenkins. This keeps the build history.


2. Implementation

Goal: Build a pipeline that compiles, tests, deploys, runs smoke tests, and generates reports.

2.1 Jenkins Setup

  1. Install Jenkins (via Docker or native).

  2. Install Plugins:

    • Pipeline
    • Maven Integration
    • Docker Pipeline Steps
    • Allure Jenkins Plugin
    • Credentials Binding
  3. Create Credentials:

    • dockerHub – username/password.
    • k8sCluster – kubeconfig.

2.2 Jenkinsfile – Declarative Pipeline

pipeline {
    agent { label 'docker' }
    environment {
        DOCKER_IMAGE = "myorg/${PROJECT_NAME}:${BUILD_NUMBER}"
        REGISTRY = 'docker.io'
    }
    stages {
        stage('Checkout') {
            steps { checkout scm }
        }
        stage('Build') {
            steps {
                sh 'mvn clean package -DskipTests'
            }
        }
        stage('Unit Tests') {
            steps {
                sh 'mvn test'
                junit 'target/surefire-reports/*.xml'
            }
        }
        stage('Docker Build') {
            steps {
                script {
                    sh """
                        docker build -t ${DOCKER_IMAGE} .
                        docker push ${DOCKER_IMAGE}
                    """
                }
            }
        }
        stage('Deploy to Staging') {
            steps {
                sh """
                    kubectl set image deployment/${PROJECT_NAME} ${PROJECT_NAME}=${DOCKER_IMAGE} --record
                    kubectl rollout status deployment/${PROJECT_NAME}
                """
            }
        }
        stage('Smoke Tests') {
            steps {
                sh 'mvn test -Dgroups=smoke'
                junit 'target/surefire-reports/*.xml'
            }
        }
        stage('Generate Reports') {
            steps {
                allure([
                    reportBuild: true,
                    reportTitle: "${PROJECT_NAME} Build ${BUILD_NUMBER}"
                ])
            }
        }
    }
    post {
        always {
            archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
        }
        failure {
            mail to: 'devops@example.com',
                 subject: "Build ${BUILD_NUMBER} Failed",
                 body: "Check Jenkins for details."
        }
    }
}

Explanation

SectionWhat it does
agent { label ‘docker’ }Runs on a Docker‑capable node.
environmentSets variables used throughout.
stage(‘Unit Tests’)Runs all tests (mvn test).
stage(‘Docker Build’)Builds the Docker image and pushes it.
stage(‘Deploy to Staging’)Uses kubectl to deploy the image.
stage(‘Smoke Tests’)Runs a subset of tests (-Dgroups=smoke).
stage(‘Generate Reports’)Publishes Allure reports.
postHandles cleanup and notifications.

2.3 Maven Build – Sample pom.xml

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>webapp</artifactId>
  <version>1.0.0</version>
  <packaging>war</packaging>

  <properties>
    <java.version>21</java.version>
    <selenium.version>4.20.0</selenium.version>
    <testng.version>7.7.0</testng.version>
  </properties>

  <dependencies>
    <!-- Production -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>3.3.2</version>
    </dependency>
    <!-- Test -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>${selenium.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>${testng.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <!-- Maven Surefire for unit tests -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.3.0</version>
        <configuration>
          <groups>smoke</groups>
        </configuration>
      </plugin>
      <!-- Allure -->
      <plugin>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-maven</artifactId>
        <version>2.10.0</version>
      </plugin>
      <!-- Docker plugin -->
      <plugin>
        <groupId>com.spotify</groupId>
        <artifactId>docker-maven-plugin</artifactId>
        <version>0.32.0</version>
      </plugin>
    </plugins>
  </build>
</project>

2.4 Selenium Test – Page Object Model

package com.example.page;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class LoginPage {
    private WebDriver driver;

    @FindBy(id = "username")
    private WebElement usernameInput;
    @FindBy(id = "password")
    private WebElement passwordInput;
    @FindBy(css = "button[type='submit']")
    private WebElement loginButton;

    public LoginPage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }

    public void login(String user, String pass) {
        usernameInput.sendKeys(user);
        passwordInput.sendKeys(pass);
        loginButton.click();
    }
}

Test Class

package com.example.tests;

import com.example.page.LoginPage;
import org.testng.annotations.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

public class SmokeLoginTest {
    @Test(groups = {"smoke"})
    public void testLogin() {
        System.setProperty("webdriver.chrome.driver", "/usr/local/bin/chromedriver");
        WebDriver driver = new ChromeDriver();
        try {
            driver.get("http://staging.example.com");
            new LoginPage(driver).login("demo", "demo123");
            // Assertions here
        } finally {
            driver.quit();
        }
    }
}

2.5 Dockerfile – Java Webapp

# Stage 1 – Build
FROM eclipse-temurin:21-jdk AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests

# Stage 2 – Runtime
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=build /app/target/webapp-1.0.0.war /app/webapp.war
RUN apt-get update && apt-get install -y tomcat9
ENV CATALINA_HOME /usr/local/tomcat
COPY tomcat-config/* ${CATALINA_HOME}/conf/
CMD ["catalina.sh", "run"]

2.6 Deployment to Staging – Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
        - name: webapp
          image: docker.io/myorg/webapp:123
          ports:
            - containerPort: 8080
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: staging

Edge Case – If the staging cluster has a network policy that restricts inbound traffic, you must expose the service with a LoadBalancer or Ingress.

2.7 Smoke Tests Post‑Deployment

Run a quick test that checks:

  1. Application is up (curl -f http://staging.example.com).
  2. Basic flows (login, create order).
  3. API health endpoint (/actuator/health).

All smoke tests are grouped with @Test(groups = {"smoke"}) and executed by Jenkins.

2.8 Test Report Generation

  • Allure – Generates interactive HTML.
  • JenkinspublishJUnitResults for test results.
  • ExtentReports – Rich UI for visualizing test coverage.

Pro Tip – Keep the report artifacts in the workspace and archive them. This lets you compare builds.


3. Advanced Topics

3.1 Pipeline as Code Best Practices

PracticeWhyHow
Version ControlTrace changesCommit Jenkinsfile in repo
Reusable LibrariesDRYJenkins Shared Libraries
Declarative over ScriptedReadabilityUse pipeline {} syntax
ParameterizationFlexibilityparameters {} block
Branch‑specific StagesCI for PRswhen { branch 'master' }
CachingSpeedcache step for Maven/Gradle

3.2 Parallel & Distributed Test Execution

stage('Run Tests') {
    parallel {
        stage('Chrome') {
            steps { sh 'mvn test -Dbrowser=chrome' }
        }
        stage('Firefox') {
            steps { sh 'mvn test -Dbrowser=firefox' }
        }
    }
}
  • Use Selenium Grid or BrowserStack for cross‑browser.
  • Leverage TestNG parallel execution (parallel="methods").

3.3 Docker‑in‑Pipeline

  • Build Docker image inside Jenkins using docker.build step.
  • Use Docker Compose to spin up dependent services (DB, Redis).
stage('Integration Tests') {
    steps {
        sh """
            docker-compose up -d
            mvn verify -Ddocker
            docker-compose down
        """
    }
}

3.4 Canary & Blue/Green Deployment

MethodHow it worksWhen to use
CanaryDeploy new version to a subset of traffic.When you need to monitor new release.
Blue/GreenTwo identical environments, switch traffic.When zero‑downtime is required.
  • In Jenkins, you can trigger a Blue/Green switch via a shell script that updates a k8s service selector.

3.5 Caching & Optimisation

ToolUse
Maven Dependency CachingCache ~/.m2/repository between builds.
Docker Layer CachingSeparate COPY of pom.xml and src/ to avoid rebuilding layers.
Parallel Stage ExecutionRun tests and deployment in parallel if independent.
Gradle Build CacheUse --build-cache for incremental builds.

Pro Tip – Use Jenkins Pipeline Caching plugin to persist artifacts across stages.

3.6 Shared Libraries

Create a src/main/groovy/ directory in a separate repo. Import it in Jenkins:

@Library('my-shared-lib@master') _

pipeline {
    agent any
    stages {
        stage('Deploy') {
            steps {
                deployToK8s('staging', 'webapp')
            }
        }
    }
}

Industry Insight – Shared libraries reduce duplication across multiple projects and centralise best‑practice code.

3.7 Security & Compliance

  • SonarQube – Static code analysis.
  • OWASP Dependency‑Check – Detect vulnerable libraries.
  • Snyk – Real‑time vulnerability scanning.

Add to pipeline:

stage('Static Analysis') {
    steps {
        sh 'mvn sonar:sonar'
    }
}

4. Real‑World Applications

DomainPipeline HighlightsCommon Challenges
E‑commerceHigh traffic, microservices, payment gateway.Load testing, data isolation.
BankingRegulatory compliance, security.Secrets management, audit logs.
MicroservicesMultiple services, inter‑service communication.Service discovery, versioning.
Continuous DeliveryFrequent releases, feature flags.Canary releases, rollback.

Use‑Case Walk‑through: E‑commerce

  1. Checkout – Pull code, run unit tests.
  2. Build – Create Docker image.
  3. Deploy – Deploy to staging via Helm.
  4. Smoke – Verify cart, checkout flows.
  5. Performance – Run Gatling tests.
  6. Security – OWASP scan.
  7. Publish – Generate Allure reports.

5. Exercises

#TaskLearning Outcome
1Create a Jenkinsfile that builds a Java project.Understand pipeline syntax.
2Add Selenium tests and run them in Jenkins.Integrate test automation.
3Build a Docker image inside Jenkins and push to Docker Hub.Docker‑in‑pipeline.
4Deploy the image to a local Minikube cluster.Kubernetes deployment.
5Implement smoke tests that verify the application after deployment.Post‑deployment validation.
6Generate Allure reports and archive them in Jenkins.Reporting.
7Optimize the pipeline by adding caching and parallel test stages.Performance tuning.
8Implement a Blue/Green deployment strategy in Jenkins.Zero‑downtime deployments.
9Add SonarQube analysis to the pipeline.Static code analysis.
10Create a Jenkins shared library that contains common deployment logic.Reusability.

Pro Tip – For each exercise, add a README.md that documents the steps, issues encountered, and solutions.


Final Takeaway

  • CI/CD is the backbone of modern Java automation testing.
  • A well‑structured Jenkinsfile keeps builds reproducible and transparent.
  • Integrating Selenium and JUnit/TestNG into the pipeline ensures early defect detection.
  • Deploying to staging and running smoke tests validates that the deployment succeeded.
  • Test reports (Allure, JUnit, Extent) provide visibility into test coverage and failures.
  • Advanced techniques – parallel execution, Docker‑in‑pipeline, shared libraries, Blue/Green – elevate the pipeline to production‑grade.

Industry Insight – The most successful teams treat their CI/CD pipeline as a product that requires continuous improvement, monitoring, and security hardening.

Happy coding, and may your pipelines run smoothly!