Master Python Payment API Automation Testing: A Complete Guide

This guide walks you through building a full‑stack Python solution for automating payment interface tests, covering workflow validation, status checks, database assertions, third‑party integration, async callbacks, and secure signing, with detailed code examples and best‑practice recommendations.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Master Python Payment API Automation Testing: A Complete Guide

In automated testing, payment interface testing is a critical and complex component that involves not only standard request/response verification but also full payment flow integrity, status change validation, database assertions, third‑party platform integration, asynchronous callback handling, and encryption signature mechanisms.

Goal

This guide provides a complete Python‑based solution for payment interface automation testing, suitable for e‑commerce, finance, SaaS and similar scenarios.

Required Tools & Tech Stack

Suggested Directory Structure

payment_automation/
├── config/
│   ├── settings.py          # Configuration (API URLs, keys, etc.)
│   └── payment_config.py    # Payment‑related settings
│
├── utils/
│   ├── http_client.py      # HTTP request wrapper
│   ├── sign_utils.py       # Signature generation utilities
│   ├── db_utils.py         # Database operation wrapper
│   └── logger.py           # Logging utilities
│
├── api/
│   ├── order_api.py        # Order creation endpoint
│   ├── payment_api.py      # Payment endpoint
│   └── notify_api.py       # Callback notification endpoint
│
├── testcases/
│   └── test_payment_flow.py # Payment flow test cases
│
├── conftest.py               # Pytest global fixtures
├── run_tests.py               # Test runner script
└── requirements.txt           # Dependency list

Core Code Implementation

1️⃣ Payment configuration (config/payment_config.py)

# config/payment_config.py
PAYMENT_CONFIG = {
    "base_url": "https://api.payment-gateway.com",
    "app_id": "your_app_id",
    "private_key": "your_private_key_here",  # Merchant private key
    "public_key": "third_party_public_key",   # Payment platform public key
    "notify_url": "https://yourdomain.com/notify"  # Async callback URL
}

2️⃣ Signature utility (utils/sign_utils.py)

# utils/sign_utils.py
import hashlib
import hmac
from urllib.parse import quote_plus

def generate_sign(params: dict, secret_key: str) -> str:
    """Generate a signature by sorting parameters and concatenating them."""
    sorted_params = "&".join(
        f"{k}={quote_plus(str(v))}" for k, v in sorted(params.items())
    )
    sign = hmac.new(secret_key.encode(), digestmod=hashlib.sha256)
    sign.update(sorted_params.encode())
    return sign.hexdigest()

3️⃣ HTTP client wrapper (utils/http_client.py)

# utils/http_client.py
import httpx
from config.payment_config import PAYMENT_CONFIG

class HttpClient:
    def __init__(self):
        self.base_url = PAYMENT_CONFIG["base_url"]
        self.headers = {"Content-Type": "application/json"}

    def post(self, endpoint: str, data: dict):
        url = f"{self.base_url}{endpoint}"
        return httpx.post(url, json=data, headers=self.headers, timeout=10)

4️⃣ Order API (api/order_api.py)

# api/order_api.py
from utils.http_client import HttpClient
from utils.sign_utils import generate_sign
from config.payment_config import PAYMENT_CONFIG

client = HttpClient()

def create_order(order_data: dict):
    """Create an order and return the order ID."""
    secret_key = PAYMENT_CONFIG["private_key"]
    order_data["sign"] = generate_sign(order_data, secret_key)
    response = client.post("/order/create", data=order_data)
    return response.json()

5️⃣ Payment API (api/payment_api.py)

# api/payment_api.py
from utils.http_client import HttpClient
from utils.sign_utils import generate_sign
from config.payment_config import PAYMENT_CONFIG

client = HttpClient()

def do_payment(payment_data: dict):
    """Initiate a payment request."""
    secret_key = PAYMENT_CONFIG["private_key"]
    payment_data["sign"] = generate_sign(payment_data, secret_key)
    response = client.post("/payment/do", data=payment_data)
    return response.json()

6️⃣ Callback simulation (api/notify_api.py)

# api/notify_api.py
from flask import Flask, request, jsonify
app = Flask(__name__)

@app.route("/notify", methods=["POST"])
def payment_notify():
    data = request.json
    print("Received payment callback:", data)
    return jsonify({"status": "success"}), 200
# Use ngrok or localtunnel to expose the local service for receiving callbacks.

7️⃣ Optional DB utility (utils/db_utils.py)

# utils/db_utils.py
import pymysql
from config.db_config import DB_CONFIG

class DBUtils:
    def __init__(self):
        self.conn = pymysql.connect(**DB_CONFIG)

    def query_order_status(self, order_id):
        with self.conn.cursor() as cursor:
            cursor.execute(f"SELECT status FROM orders WHERE id='{order_id}'")
            result = cursor.fetchone()
            return result[0] if result else None

8️⃣ Test case example (testcases/test_payment_flow.py)

# testcases/test_payment_flow.py
import pytest
from api.order_api import create_order
from api.payment_api import do_payment
from utils.db_utils import DBUtils

@pytest.fixture
def db_utils():
    return DBUtils()

def test_payment_flow(db_utils):
    # Step 1: Create order
    order_data = {
        "user_id": "U1001",
        "product_id": "P2001",
        "amount": 99.9,
        "timestamp": "20250405120000"
    }
    order_response = create_order(order_data)
    order_id = order_response.get("order_id")
    assert order_id is not None, "Order creation failed"

    # Step 2: Initiate payment
    payment_data = {
        "order_id": order_id,
        "pay_type": "wechat",
        "timestamp": "20250405120010"
    }
    payment_response = do_payment(payment_data)
    assert payment_response.get("code") == "200", "Payment failed"

    # Step 3: Wait for callback (or poll DB)
    import time
    time.sleep(5)  # Simulate async notification delay

    # Step 4: Database assertion
    status = db_utils.query_order_status(order_id)
    assert status == "paid", f"Order status not updated, current: {status}"

Running Tests & Viewing Reports

pip install -r requirements.txt
python run_tests.py
# Generate Allure report
pytest testcases/ --alluredir=./reports/allure
allure serve ./reports/allure

Advanced Tips & Considerations

Key points for payment interface testing include handling encryption, managing async callbacks, and ensuring data consistency across services.

Recommended Practices

Read all sensitive information (e.g., keys) from environment variables instead of hard‑coding.

Use a .env file with python‑dotenv for configuration management.

Generate test data with faker (users, product IDs, etc.).

Build a local test environment with docker‑compose (MySQL, Redis, Flask callback service).

Integrate the test framework into CI/CD pipelines (Jenkins, GitHub Actions).

Optional Enhancements

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

API testingpytestpython testingpayment automation
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.