python自动化测试框架
import time import datetime from docx import Document from docx.shared import Inches, Pt, RGBColor from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.enum.table import WD_TABLE_ALIGNMENT from docx.oxml import OxmlElement from docx.oxml.ns import qn from playwright.sync_api import sync_playwright, expect # ========================= Word 报告生成模块 ========================= def set_cell_background(cell, fill_hex): """设置 Word 单元格背景颜色""" tcPr = cell._element.get_or_add_tcPr() shd = OxmlElement('w:shd') shd.set(qn('w:val'), 'clear') shd.set(qn('w:color'), 'auto') shd.set(qn('w:fill'), fill_hex) tcPr.append(shd) def generate_word_report(results, report_path="自动化测试结果报告.docx"): """生成自动化测试报告 Word 文档""" doc = Document() # 1. 报告大标题 title = doc.add_heading("XXXX Web UI 自动化测试报告", level=0) title.alignment = WD_ALIGN_PARAGRAPH.CENTER # 2. 统计数据 total = len(results) passed = sum(1 for r in results if r["status"] == "PASS") failed = total - passed pass_rate = f"{(passed / total * 100):.1f}%" if total > 0 else "0%" # 3. 基本信息 p_meta = doc.add_paragraph() p_meta.add_run(f"执行时间:{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n").font.size = Pt(10) p_meta.add_run(f"测试环境:https://stageassp.XXXXX.com/asm/#/\n").font.size = Pt(10) p_meta.add_run(f"执行机制:单步异常捕获并自动跳过\n").font.size = Pt(10) # 4. 执行概览卡片 doc.add_heading("一、 测试执行概览", level=1) summary_table = doc.add_table(rows=2, cols=4) summary_table.alignment = WD_TABLE_ALIGNMENT.CENTER headers = ["执行总数", "成功用例 (PASS)", "失败用例 (FAIL)", "测试通过率"] for i, h in enumerate(headers): cell = summary_table.cell(0, i) cell.text = h cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER cell.paragraphs[0].runs[0].font.bold = True cell.paragraphs[0].runs[0].font.color.rgb = RGBColor(255, 255, 255) set_cell_background(cell, "1F4E79") values = [str(total), str(passed), str(failed), pass_rate] text_colors = ["333333", "2E7D32", "C62828" if failed > 0 else "333333", "1F4E79"] for i, v in enumerate(values): cell = summary_table.cell(1, i) cell.text = v cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER run = cell.paragraphs[0].runs[0] run.font.bold = True run.font.size = Pt(13) r, g, b = int(text_colors[i][0:2], 16), int(text_colors[i][2:4], 16), int(text_colors[i][4:6], 16) run.font.color.rgb = RGBColor(r, g, b) set_cell_background(cell, "F2F4F7") doc.add_paragraph("") # 5. 详细明细表 doc.add_heading("二、 用例执行明细", level=1) detail_table = doc.add_table(rows=1, cols=6) detail_table.alignment = WD_TABLE_ALIGNMENT.CENTER d_headers = ["序号", "测试步骤 / 用例名称", "预期结果", "实际执行结果", "耗时(秒)", "测试状态"] widths = [Inches(0.6), Inches(1.8), Inches(1.5), Inches(1.8), Inches(0.8), Inches(0.9)] for i, h in enumerate(d_headers): cell = detail_table.cell(0, i) cell.text = h cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER cell.paragraphs[0].runs[0].font.bold = True cell.paragraphs[0].runs[0].font.color.rgb = RGBColor(255, 255, 255) set_cell_background(cell, "2E5B88") cell.width = widths[i] for idx, r in enumerate(results, start=1): row = detail_table.add_row() vals = [str(idx), r["name"], r["expect"], r["actual"], f"{r['duration']:.2f}", r["status"]] for col_idx, val in enumerate(vals): cell = row.cells[col_idx] cell.text = val cell.width = widths[col_idx] p = cell.paragraphs[0] if col_idx in [0, 4, 5]: p.alignment = WD_ALIGN_PARAGRAPH.CENTER # 状态列高亮 if col_idx == 5: run = p.runs[0] run.font.bold = True if val == "PASS": run.font.color.rgb = RGBColor(46, 125, 50) set_cell_background(cell, "E8F5E9") else: run.font.color.rgb = RGBColor(198, 40, 40) set_cell_background(cell, "FFEBEE") doc.save(report_path) print(f"\n📄 [Word报告生成完毕] -> {report_path}") # ========================= 自动化测试调度器 ========================= def run_automation_suite(): results = [] def record_step(page, name, expect_desc, func): """ 核心异常处理与用例记录: - 成功:记录为 PASS - 失败:捕获异常,记录为 FAIL,打印错误信息,【不中断程序,安全跳过继续执行下一步】 """ t0 = time.time() print(f"\n👉 正在执行:{name} ...") try: actual_msg = func(page) or "执行正常完成" duration = time.time() - t0 results.append({ "name": name, "expect": expect_desc, "actual": str(actual_msg), "duration": duration, "status": "PASS" }) print(f" ✅ [PASS] 耗时: {duration:.2f}s | {actual_msg}") return True except Exception as e: duration = time.time() - t0 err_line = str(e).split("\n")[0][:120] # 截取主要错误原因 results.append({ "name": name, "expect": expect_desc, "actual": f"执行失败: {err_line}", "duration": duration, "status": "FAIL" }) print(f" ❌ [FAIL] 耗时: {duration:.2f}s | 错误: {err_line}") print(" ⚠️ [已触发容错] 自动跳过当前用例,继续执行下一项...") # 页面状态容错恢复:按 Escape 键尝试关闭可能卡住的下拉菜单或遮罩层 try: page.keyboard.press("Escape") page.wait_for_timeout(500) except Exception: pass return False with sync_playwright() as p: browser = p.chromium.launch(headless=False, slow_mo=200) page = browser.new_page() # ================= 各用例独立定义 ================= def tc_01_login(pg): pg.goto("https://stageassp.xxxx.com/asm/#/") pg.wait_for_load_state("domcontentloaded") pg.get_by_placeholder("请输入账号名称").fill("xxxx") pg.get_by_placeholder("请输入您的密码").fill("xxxx") pg.get_by_role("button", name="登 录").click() expect(pg.get_by_text("登录成功")).to_be_visible(timeout=8000) pg.wait_for_load_state("networkidle") return "弹出【登录成功】提示,进入系统首页" def tc_02_nav_order_list(pg): pg.get_by_text("工单管理").click() pg.wait_for_timeout(500) pg.get_by_text("工单列表").click() pg.wait_for_load_state("networkidle") return "成功进入工单列表页面" # ================= 用例注册调度列表 ================= # 💡 如果要添加新用例,直接在这下面添加一行元组即可! test_cases = [ ("TC01 - 系统登录", "弹出登录成功并跳转主页", tc_01_login), ("TC02 - 导航到工单列表", "成功展开菜单并进入列表页", tc_02_nav_order_list), # 如需扩展: # ("TC05 - 新用例名称", "预期结果描述", 自定义用例函数名), ] # 逐个执行(失败跳过不中断) for name, expect_desc, func in test_cases: record_step(page, name, expect_desc, func) page.wait_for_timeout(2000) browser.close() # 生成 Word 报告 generate_word_report(results, report_path="自动化测试结果报告.docx") if __name__ == "__main__": run_automation_suite()
增加测试用例的方法
1.增加测试函数定义如:
def tc_03_logout(pg):
2 在test case里增加用例定义
test_cases = [
("TC01 - 系统登录", "弹出登录成功并跳转主页", tc_01_login),
("TC02 - 导航到工单列表", "成功展开菜单并进入列表页", tc_02_nav_order_list),
# 如需扩展:
# ("TC05 - 新用例名称", "预期结果描述", 自定义用例函数名),

浙公网安备 33010602011771号