Iterative Debugging of AI‑Generated Test Cases and Scripts (Part 4)

The article outlines a lightweight AI‑agent workflow that iteratively refines Python‑based Playwright/pytest test scripts by combining human review with AI‑generated suggestions, shows the exact system and user prompts, and provides a complete runnable example with database setup, request handling, and a failing test case to illustrate the debugging loop.

Woodpecker Software Testing
Woodpecker Software Testing
Woodpecker Software Testing
Iterative Debugging of AI‑Generated Test Cases and Scripts (Part 4)

The author extends the series on using an intelligent agent to generate test cases and scripts by introducing a simple online debugging flow. The workflow consists of a start node and a single AI node named "Optimize Test Script" that repeatedly receives the current script and error information, then returns an improved version.

System and User Prompts

System Prompt: "You are a senior software test development engineer proficient in Python, Playwright and pytest. Your core responsibility is to optimize the test script based on ${sys.query}."

User Prompt: "You are a senior software test development engineer proficient in Python, Playwright and pytest. Your core responsibility is to optimize the test script based on ${sys.query}."

During execution, the user must describe the test script and any error messages clearly; by iterating this exchange, the script is gradually improved.

Full Example Test Script

import unittest
import requests
import hashlib
import re
import pymysql
from parameterized import parameterized
from bs4 import BeautifulSoup
import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# Database configuration (keep encoding consistent with backend)
DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': '123456',
    'database': 'chatgptebusiness',
    'charset': 'utf8'
}

# API endpoints
VERICODE_URL = "http://127.0.0.1:8080/ChatGPTEbusiness/jsp/VeriCodePage.jsp"
RECOVER_URL = "http://127.0.0.1:8080/ChatGPTEbusiness/jsp/RecoverPage.jsp"

class RecoverPasswordAPITest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        """Initialize class‑level resources: DB connection and HTTP session"""
        cls.db = pymysql.connect(**DB_CONFIG)
        cls.session = requests.Session()
        logger.info("Class-level setup completed")

    @classmethod
    def tearDownClass(cls):
        """Clean up class‑level resources"""
        cls.db.close()
        cls.session.close()
        logger.info("Class-level teardown completed")

    def setUp(self):
        """Before each test: clear tables and obtain initial CSRF token"""
        self._clear_tables()
        self.csrf_token = self._get_csrf_token(VERICODE_URL)
        logger.info("Test setup completed: %s", self._testMethodName)

    def tearDown(self):
        """After each test: ensure a clean environment"""
        logger.info("Test teardown completed: %s", self._testMethodName)

    def _clear_tables(self):
        """Empty relevant DB tables"""
        try:
            with self.db.cursor() as cursor:
                cursor.execute("SET FOREIGN_KEY_CHECKS = 0")
                cursor.execute("DELETE FROM user")
                cursor.execute("DELETE FROM code")
                cursor.execute("SET FOREIGN_KEY_CHECKS = 1")
                self.db.commit()
            logger.info("Database tables cleared")
        except Exception as e:
            self.fail(f"Database clear failed: {str(e)}")

    def _get_csrf_token(self, url):
        """Extract CSRF token from the page"""
        try:
            response = self.session.get(url)
            response.raise_for_status()
            match = re.search(r'<input type="hidden" id="csrftoken" name="csrftoken" value="([^\"]+)"', response.text)
            return match.group(1) if match else None
        except Exception as e:
            logger.error("CSRF token retrieval failed: %s", str(e))
            self.fail(f"Get CSRF token failed: {str(e)}")

    def _hash_password(self, password):
        """Compute password hash using the backend's algorithm"""
        return hashlib.sha256(password.encode('utf-8')).hexdigest()

    def _post_vericode(self, contact):
        """Send verification request for phone/email"""
        data = {"csrftoken": self.csrf_token, "contact": contact}
        response = self.session.post(VERICODE_URL, data=data, cookies={"csrftoken": self.csrf_token})
        response.raise_for_status()
        return response

    def _post_resetcode(self, identifying_code, new_password, confirm_password):
        """Submit new password (backend expects plaintext)"""
        self.csrf_token = self._get_csrf_token(RECOVER_URL)
        data = {
            "csrftoken": self.csrf_token,
            "identifyingCode": identifying_code,
            "newPassword": new_password,   # send plaintext
            "confirmPassword": confirm_password
        }
        response = self.session.post(RECOVER_URL, data=data, cookies={"csrftoken": self.csrf_token})
        response.raise_for_status()
        return response

    def _get_error_message(self, response):
        """Parse error message from HTML response"""
        try:
            soup = BeautifulSoup(response.text, 'html.parser')
            error_div = soup.find('div', id='recoverError')
            return error_div.get_text(strip=True) if error_div else ""
        except Exception:
            return ""

    @parameterized.expand([
        ("有效手机号", "13800138000", True, "成功"),
        ("有效邮箱", "[email protected]", True, "成功"),
    ])
    def test_verify_contact(self, test_name, contact, is_success, expected_msg):
        """Test verification endpoint (001 series)"""
        if is_success:
            try:
                with self.db.cursor() as cursor:
                    old_password = "oldpass123"
                    first_hash = self._hash_password(old_password)
                    cursor.execute("INSERT INTO user (phone, password) VALUES (%s, %s)", (contact, first_hash))
                    self.db.commit()
                logger.info("Test user created: %s", contact)
            except Exception as e:
                self.fail(f"Failed to create test user: {str(e)}")
        response = self._post_vericode(contact)
        self.assertEqual(response.status_code, 200)
        if is_success:
            self.assertIn("找回密码", response.text)
        else:
            error_msg = self._get_error_message(response)
            self.assertEqual(error_msg, expected_msg)

    @parameterized.expand([
        ("正确验证码和密码", "13800138000", "123456", "Abc123", "Abc123", "成功"),
    ])
    def test_reset_password(self, test_name, contact, code, new_password, confirm_password, expected_msg):
        """Test password‑reset endpoint (002 series)"""
        try:
            with self.db.cursor() as cursor:
                old_password = "oldpass123"
                first_hash = self._hash_password(old_password)
                cursor.execute("INSERT INTO user (phone, password) VALUES (%s, %s)", (contact, first_hash))
                user_id = cursor.lastrowid
                self.db.commit()
                cursor.execute("INSERT INTO code (uid, code) VALUES (%s, %s)", (user_id, code))
                self.db.commit()
            logger.info("Test data created: user_id=%s, contact=%s", user_id, contact)
        except Exception as e:
            self.fail(f"Failed to create test data: {str(e)}")

        response = self._post_resetcode(code, new_password, confirm_password)
        self.assertEqual(response.status_code, 200)

        if "成功" in expected_msg:
            try:
                with self.db.cursor() as cursor:
                    cursor.execute("SELECT password FROM user WHERE id = %s", (user_id,))
                    result = cursor.fetchone()
                    self.assertIsNotNone(result, "User record not updated")
                    first_hash = self._hash_password(new_password)
                    expected_hash = first_hash
                    logger.info("Calculated hash: %s (for password: '%s')", expected_hash, new_password)
                    logger.info("Database hash: %s", result[0])
                    self.assertEqual(expected_hash, result[0],
                        f"Password hash mismatch: expected '{expected_hash}', got '{result[0]}'")
            except Exception as e:
                self.fail(f"Database verification failed: {str(e)}")
        else:
            error_msg = self._get_error_message(response)
            self.assertEqual(error_msg, expected_msg)

if __name__ == "__main__":
    unittest.main(verbosity=2, failfast=True)

The author notes that AI‑generated scripts rarely work perfectly on the first try; therefore the human must run the script, capture the failure details, feed them back to the agent via the prompts, and let the agent propose corrections. This loop continues until the test passes.

Running the provided test reveals a hash mismatch failure: the expected SHA‑256 of the new password is

7f91e8a4b648b0125b15dc5a3b6466f9f4906d92c72bea9bd6be92c853bebda2

, but the database stores

04e45016090b3ae8bac292e00f912ca04d2f93b0b0a51f5b22ccf40c7123df1a

. The author uses this example to demonstrate how the debugging workflow surfaces such discrepancies, prompting the agent to adjust the hashing logic or the test data preparation.

Two diagrams (included as images) illustrate the overall flow and the position of the AI node within the debugging pipeline.

Workflow diagram
Workflow diagram
Agent node illustration
Agent node illustration
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.

Pythonsoftware testingtest automationAI AgentPlaywrightpytestdatabase testing
Woodpecker Software Testing
Written by

Woodpecker Software Testing

The Woodpecker Software Testing public account shares software testing knowledge, connects testing enthusiasts, founded by Gu Xiang, website: www.3testing.com. Author of five books, including "Mastering JMeter Through Case Studies".

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.