Add payment test suite with Jenkins CI/CD integration

This commit is contained in:
pavan-msys 2026-05-06 12:01:34 +05:30
parent 141a64342c
commit a4adc2e219
10 changed files with 780 additions and 1 deletions

43
.gitignore vendored Normal file
View File

@ -0,0 +1,43 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
ENV/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Testing
.pytest_cache/
.coverage
htmlcov/
test-results.xml
test-report.html
coverage.xml
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db

94
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,94 @@
pipeline {
agent any
environment {
PYTHON_VERSION = '3.9'
}
stages {
stage('Checkout') {
steps {
echo 'Checking out code...'
checkout scm
}
}
stage('Setup Python Environment') {
steps {
echo 'Setting up Python environment...'
bat '''
python --version
python -m pip install --upgrade pip
'''
}
}
stage('Install Dependencies') {
steps {
echo 'Installing dependencies...'
bat '''
pip install -r requirements.txt
'''
}
}
stage('Run Tests') {
steps {
echo 'Running payment tests...'
bat '''
pytest tests/ -v --junitxml=test-results.xml --html=test-report.html --self-contained-html
'''
}
}
stage('Code Coverage') {
steps {
echo 'Generating code coverage report...'
bat '''
pytest tests/ --cov=src --cov-report=html --cov-report=xml
'''
}
}
stage('Publish Results') {
steps {
echo 'Publishing test results...'
junit 'test-results.xml'
publishHTML(target: [
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'htmlcov',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
publishHTML(target: [
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: '.',
reportFiles: 'test-report.html',
reportName: 'Test Report'
])
}
}
}
post {
always {
echo 'Cleaning up...'
cleanWs(patterns: [
[pattern: '**/__pycache__', type: 'INCLUDE'],
[pattern: '**/*.pyc', type: 'INCLUDE']
])
}
success {
echo 'Pipeline completed successfully!'
}
failure {
echo 'Pipeline failed!'
}
}
}

56
README
View File

@ -1 +1,55 @@
Hello World!
# Hello World - Payment Test Suite
This repository contains a dummy payment service with comprehensive test cases designed to run through Jenkins CI/CD pipeline.
## Quick Start
### Run Tests Locally
```bash
pip install -r requirements.txt
pytest tests/ -v
```
### View Coverage
```bash
pytest tests/ --cov=src --cov-report=html
```
## What's Included
- **Payment Service**: Dummy payment processing module
- **21 Test Cases**: Comprehensive test coverage including positive, negative, and edge cases
- **Jenkins Pipeline**: Automated CI/CD configuration
- **Coverage Reports**: HTML and XML coverage reporting
## Documentation
See [SETUP_GUIDE.md](SETUP_GUIDE.md) for complete setup instructions and Jenkins configuration.
## Test Results
The test suite includes:
- ✅ 4 Positive test cases
- ❌ 8 Negative test cases
- 🔍 9 Edge case tests
Total: **21 automated tests**
## Jenkins Integration
This project includes a complete Jenkinsfile that:
1. Checks out code
2. Sets up Python environment
3. Installs dependencies
4. Runs all tests
5. Generates coverage reports
6. Publishes results
## Project Structure
```
Hello-World/
├── src/ # Payment service source code
├── tests/ # Test cases
├── Jenkinsfile # Jenkins pipeline
└── requirements.txt # Dependencies
```

271
SETUP_GUIDE.md Normal file
View File

@ -0,0 +1,271 @@
# Payment Test Suite - Jenkins Setup Guide
## Project Structure
```
Hello-World/
├── src/
│ ├── __init__.py
│ └── payment_service.py # Dummy payment service
├── tests/
│ ├── __init__.py
│ └── test_payment.py # Payment test cases (21 tests)
├── Jenkinsfile # Jenkins pipeline configuration
├── requirements.txt # Python dependencies
├── pytest.ini # Pytest configuration
├── .gitignore # Git ignore patterns
├── SETUP_GUIDE.md # This file
└── README # Original readme
```
## Test Cases Included
The test suite includes **21 comprehensive test cases**:
### Positive Tests
1. ✅ Successful payment processing
2. ✅ Multiple payments handling
3. ✅ Transaction retrieval
4. ✅ Successful refund processing
### Negative Tests
5. ❌ Invalid amount (zero)
6. ❌ Invalid amount (negative)
7. ❌ Invalid card number (too short)
8. ❌ Invalid card number (empty)
9. ❌ Invalid CVV (too short)
10. ❌ Invalid CVV (empty)
11. ❌ Refund non-existent transaction
12. ❌ Duplicate refund
### Edge Cases
13. 🔍 Large amount payment
14. 🔍 Small amount payment
15. 🔍 Get all transactions (empty)
16. 🔍 Get non-existent transaction
17. 🔍 Card number masking
## Prerequisites
### Local Setup
1. **Python 3.9+** installed
2. **Git** installed
3. **pip** package manager
### Jenkins Setup
1. **Jenkins** server installed and running
2. **Python plugin** for Jenkins
3. **HTML Publisher plugin** for Jenkins
4. **JUnit plugin** for Jenkins (usually pre-installed)
## Step-by-Step Procedure
### Part 1: Local Testing (Optional but Recommended)
1. **Clone/Navigate to your repository:**
```bash
cd d:\Hello-World
```
2. **Install dependencies:**
```bash
pip install -r requirements.txt
```
3. **Run tests locally:**
```bash
# Run all tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=src --cov-report=html
# Run specific test
pytest tests/test_payment.py::TestPaymentService::test_successful_payment -v
```
4. **View coverage report:**
```bash
# Open htmlcov/index.html in your browser
start htmlcov/index.html
```
### Part 2: Jenkins Setup
#### Option A: Jenkins Pipeline (Recommended)
1. **Install Required Jenkins Plugins:**
- Go to Jenkins → Manage Jenkins → Manage Plugins
- Install:
- Pipeline
- Git plugin
- HTML Publisher plugin
- JUnit plugin
2. **Create New Jenkins Job:**
- Click "New Item"
- Enter job name: `Payment-Test-Suite`
- Select "Pipeline"
- Click OK
3. **Configure Pipeline:**
- Scroll to "Pipeline" section
- Definition: Select "Pipeline script from SCM"
- SCM: Select "Git"
- Repository URL: Enter your Git repository URL
- Branch: `*/main` (or your default branch)
- Script Path: `Jenkinsfile`
- Click "Save"
4. **Run the Pipeline:**
- Click "Build Now"
- Monitor the build in the console output
#### Option B: Freestyle Project
1. **Create New Jenkins Job:**
- Click "New Item"
- Enter job name: `Payment-Test-Suite-Freestyle`
- Select "Freestyle project"
- Click OK
2. **Source Code Management:**
- Select "Git"
- Repository URL: Enter your repository URL
- Branch: `*/main`
3. **Build Steps:**
- Add build step → Execute Windows batch command
```batch
python -m pip install --upgrade pip
pip install -r requirements.txt
pytest tests/ -v --junitxml=test-results.xml --html=test-report.html --self-contained-html
pytest tests/ --cov=src --cov-report=html --cov-report=xml
```
4. **Post-build Actions:**
- Add "Publish JUnit test result report"
- Test report XMLs: `test-results.xml`
- Add "Publish HTML reports"
- HTML directory to archive: `htmlcov`
- Index page: `index.html`
- Report title: `Coverage Report`
5. **Save and Build:**
- Click "Save"
- Click "Build Now"
### Part 3: GitHub/Git Integration
1. **Push your code to Git:**
```bash
git add .
git commit -m "Add payment test suite and Jenkins pipeline"
git push origin main
```
2. **Configure Webhook (Optional - for automatic builds):**
- In GitHub: Settings → Webhooks → Add webhook
- Payload URL: `http://your-jenkins-url/github-webhook/`
- Content type: `application/json`
- Select: "Just the push event"
- Active: ✓
3. **In Jenkins Job Configuration:**
- Build Triggers → Check "GitHub hook trigger for GITScm polling"
### Part 4: Viewing Results
After a successful build, you can view:
1. **Test Results:**
- Click on build number → Test Results
- Shows all 21 test cases with pass/fail status
2. **Coverage Report:**
- Click on build number → Coverage Report
- Shows code coverage percentage
3. **HTML Test Report:**
- Click on build number → Test Report
- Detailed HTML report with test execution details
4. **Console Output:**
- Click on build number → Console Output
- View complete build log
## Jenkins Pipeline Stages
The Jenkinsfile includes these stages:
1. **Checkout** - Pulls code from repository
2. **Setup Python Environment** - Verifies Python installation
3. **Install Dependencies** - Installs required packages
4. **Run Tests** - Executes all test cases
5. **Code Coverage** - Generates coverage report
6. **Publish Results** - Publishes test and coverage reports
## Troubleshooting
### Common Issues
1. **Python not found:**
- Add Python to system PATH
- In Jenkins: Manage Jenkins → Global Tool Configuration → Add Python
2. **Module not found:**
- Ensure `requirements.txt` is installed
- Check virtual environment activation
3. **Tests not discovered:**
- Verify pytest.ini configuration
- Check test file naming (test_*.py)
4. **HTML reports not showing:**
- Install HTML Publisher plugin
- Configure Content Security Policy:
```
Manage Jenkins → Script Console → Run:
System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")
```
## Running Specific Test Categories
```bash
# Run only successful payment tests
pytest tests/test_payment.py -k "successful" -v
# Run only negative tests
pytest tests/test_payment.py -k "invalid" -v
# Run with markers (if configured)
pytest tests/ -m "unit" -v
```
## CI/CD Best Practices
1. **Run tests on every commit**
2. **Maintain >80% code coverage**
3. **Review failed tests immediately**
4. **Keep test execution time < 5 minutes**
5. **Archive test reports for compliance**
## Next Steps
1. Add more test cases for edge scenarios
2. Integrate with Slack/Email for notifications
3. Add performance testing
4. Implement test data management
5. Add security scanning stages
## Support
For issues or questions:
- Check Jenkins console output
- Review test logs in test-report.html
- Verify Python and dependency versions
---
**Last Updated:** May 2026

23
pytest.ini Normal file
View File

@ -0,0 +1,23 @@
[pytest]
# Pytest configuration file
# Test discovery patterns
python_files = test_*.py
python_classes = Test*
python_functions = test_*
# Test paths
testpaths = tests
# Output options
addopts =
-v
--strict-markers
--tb=short
--disable-warnings
# Markers
markers =
slow: marks tests as slow
integration: marks tests as integration tests
unit: marks tests as unit tests

7
requirements.txt Normal file
View File

@ -0,0 +1,7 @@
# Testing Dependencies
pytest==7.4.3
pytest-html==4.1.1
pytest-cov==4.1.0
# Code Quality
flake8==6.1.0

1
src/__init__.py Normal file
View File

@ -0,0 +1 @@
# Payment Service Package

117
src/payment_service.py Normal file
View File

@ -0,0 +1,117 @@
"""
Dummy Payment Service for Testing
"""
class PaymentService:
"""Simple payment service for demonstration"""
def __init__(self):
self.transactions = []
def process_payment(self, amount, card_number, cvv):
"""
Process a payment transaction
Args:
amount (float): Payment amount
card_number (str): Card number
cvv (str): CVV code
Returns:
dict: Transaction result
"""
if amount <= 0:
return {
"status": "failed",
"message": "Invalid amount",
"transaction_id": None
}
if not card_number or len(card_number) != 16:
return {
"status": "failed",
"message": "Invalid card number",
"transaction_id": None
}
if not cvv or len(cvv) != 3:
return {
"status": "failed",
"message": "Invalid CVV",
"transaction_id": None
}
transaction_id = f"TXN{len(self.transactions) + 1:06d}"
transaction = {
"transaction_id": transaction_id,
"amount": amount,
"card_number": f"****{card_number[-4:]}",
"status": "success"
}
self.transactions.append(transaction)
return {
"status": "success",
"message": "Payment processed successfully",
"transaction_id": transaction_id
}
def refund_payment(self, transaction_id):
"""
Refund a payment
Args:
transaction_id (str): Transaction ID to refund
Returns:
dict: Refund result
"""
transaction = next(
(t for t in self.transactions if t["transaction_id"] == transaction_id),
None
)
if not transaction:
return {
"status": "failed",
"message": "Transaction not found"
}
if transaction.get("refunded"):
return {
"status": "failed",
"message": "Transaction already refunded"
}
transaction["refunded"] = True
return {
"status": "success",
"message": "Refund processed successfully",
"transaction_id": transaction_id
}
def get_transaction(self, transaction_id):
"""
Get transaction details
Args:
transaction_id (str): Transaction ID
Returns:
dict: Transaction details or None
"""
return next(
(t for t in self.transactions if t["transaction_id"] == transaction_id),
None
)
def get_all_transactions(self):
"""
Get all transactions
Returns:
list: All transactions
"""
return self.transactions.copy()

1
tests/__init__.py Normal file
View File

@ -0,0 +1 @@
# Test Package

168
tests/test_payment.py Normal file
View File

@ -0,0 +1,168 @@
"""
Test cases for Payment Service
"""
import pytest
import sys
import os
# Add src directory to path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'src')))
from payment_service import PaymentService
class TestPaymentService:
"""Test suite for PaymentService"""
@pytest.fixture
def payment_service(self):
"""Create a fresh payment service instance for each test"""
return PaymentService()
# Positive Test Cases
def test_successful_payment(self, payment_service):
"""Test successful payment processing"""
result = payment_service.process_payment(
amount=100.50,
card_number="1234567890123456",
cvv="123"
)
assert result["status"] == "success"
assert result["transaction_id"] is not None
assert result["message"] == "Payment processed successfully"
def test_multiple_payments(self, payment_service):
"""Test processing multiple payments"""
result1 = payment_service.process_payment(100.00, "1234567890123456", "123")
result2 = payment_service.process_payment(200.00, "9876543210987654", "456")
assert result1["status"] == "success"
assert result2["status"] == "success"
assert result1["transaction_id"] != result2["transaction_id"]
assert len(payment_service.get_all_transactions()) == 2
def test_get_transaction(self, payment_service):
"""Test retrieving transaction details"""
result = payment_service.process_payment(150.00, "1234567890123456", "123")
transaction_id = result["transaction_id"]
transaction = payment_service.get_transaction(transaction_id)
assert transaction is not None
assert transaction["transaction_id"] == transaction_id
assert transaction["amount"] == 150.00
def test_successful_refund(self, payment_service):
"""Test successful refund processing"""
# First make a payment
payment_result = payment_service.process_payment(100.00, "1234567890123456", "123")
transaction_id = payment_result["transaction_id"]
# Then refund it
refund_result = payment_service.refund_payment(transaction_id)
assert refund_result["status"] == "success"
assert refund_result["message"] == "Refund processed successfully"
# Negative Test Cases
def test_invalid_amount_zero(self, payment_service):
"""Test payment with zero amount"""
result = payment_service.process_payment(0, "1234567890123456", "123")
assert result["status"] == "failed"
assert result["message"] == "Invalid amount"
assert result["transaction_id"] is None
def test_invalid_amount_negative(self, payment_service):
"""Test payment with negative amount"""
result = payment_service.process_payment(-50.00, "1234567890123456", "123")
assert result["status"] == "failed"
assert result["message"] == "Invalid amount"
def test_invalid_card_number_short(self, payment_service):
"""Test payment with short card number"""
result = payment_service.process_payment(100.00, "123456", "123")
assert result["status"] == "failed"
assert result["message"] == "Invalid card number"
def test_invalid_card_number_empty(self, payment_service):
"""Test payment with empty card number"""
result = payment_service.process_payment(100.00, "", "123")
assert result["status"] == "failed"
assert result["message"] == "Invalid card number"
def test_invalid_cvv_short(self, payment_service):
"""Test payment with short CVV"""
result = payment_service.process_payment(100.00, "1234567890123456", "12")
assert result["status"] == "failed"
assert result["message"] == "Invalid CVV"
def test_invalid_cvv_empty(self, payment_service):
"""Test payment with empty CVV"""
result = payment_service.process_payment(100.00, "1234567890123456", "")
assert result["status"] == "failed"
assert result["message"] == "Invalid CVV"
def test_refund_nonexistent_transaction(self, payment_service):
"""Test refunding a transaction that doesn't exist"""
result = payment_service.refund_payment("TXN999999")
assert result["status"] == "failed"
assert result["message"] == "Transaction not found"
def test_duplicate_refund(self, payment_service):
"""Test refunding the same transaction twice"""
# Make a payment
payment_result = payment_service.process_payment(100.00, "1234567890123456", "123")
transaction_id = payment_result["transaction_id"]
# First refund should succeed
refund1 = payment_service.refund_payment(transaction_id)
assert refund1["status"] == "success"
# Second refund should fail
refund2 = payment_service.refund_payment(transaction_id)
assert refund2["status"] == "failed"
assert refund2["message"] == "Transaction already refunded"
# Edge Cases
def test_large_amount_payment(self, payment_service):
"""Test payment with large amount"""
result = payment_service.process_payment(999999.99, "1234567890123456", "123")
assert result["status"] == "success"
def test_small_amount_payment(self, payment_service):
"""Test payment with small valid amount"""
result = payment_service.process_payment(0.01, "1234567890123456", "123")
assert result["status"] == "success"
def test_get_all_transactions_empty(self, payment_service):
"""Test getting all transactions when none exist"""
transactions = payment_service.get_all_transactions()
assert transactions == []
def test_get_nonexistent_transaction(self, payment_service):
"""Test getting a transaction that doesn't exist"""
transaction = payment_service.get_transaction("TXN999999")
assert transaction is None
def test_card_number_masking(self, payment_service):
"""Test that card numbers are properly masked in transactions"""
payment_service.process_payment(100.00, "1234567890123456", "123")
transaction = payment_service.get_all_transactions()[0]
assert transaction["card_number"] == "****3456"
assert "1234567890123456" not in str(transaction)