test(物流公司管理需求): 需求文档与 QE Fleet 全流程设计产物入库

- 需求 v1.1 + 2026-09-29 需求方确认的 Q7~Q19 决议(含 BR-07/BR-09/6.7/6.9 矛盾表述修订)
- 测试点 159 个、测试用例 164 条(P0 55/P1 81/P2 23/P3 5),需求→测试点→用例三级追溯覆盖率 100%
- 质量裁决 PASS(首轮 PASS_WITH_FIX,13 项待确认确认后复裁决升级);评审原始 2 阻断项+9 建议项+3 优化项已全部修复
- 确认单:与 4 个历史需求均为并行关系、0 冲突、0 回写
- 附导出 v1/v2 版本快照、Playwright/Appium 脚本骨架、覆盖率审计脚本与指标、评审修复脚本
This commit is contained in:
xst
2026-09-29 10:03:35 +08:00
parent 1a53a1f537
commit 8c61209dd4
47 changed files with 14470 additions and 0 deletions
@@ -0,0 +1,172 @@
"""
Agentic QE Fleet — Appium 移动端自动化测试脚本
需求: 物流公司管理需求
生成时间: 2026-09-29T00:22:25.374685+00:00
目标平台: android, ios
对应测试用例: E:\Desktop\xst_files\test\QaAutomationHub\output\test_cases\物流公司管理需求_测试用例.md
"""
import time
from pathlib import Path
from datetime import datetime
# Appium 客户端 (需要 pip install Appium-Python-Client)
try:
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.options.ios import XCUITestOptions
APPIUM_AVAILABLE = True
except ImportError:
APPIUM_AVAILABLE = False
print("⚠️ Appium-Python-Client 未安装,请执行: pip install Appium-Python-Client")
SCREENSHOTS_DIR = Path(r"E:\Desktop\xst_files\test\QaAutomationHub\output\screenshots\物流公司管理需求")
SCREENSHOT_ON_FAILURE = True
# Appium Server 配置
APPIUM_HOST = "http://localhost:4723"
# 设备配置模板(请根据实际测试设备修改)
ANDROID_CAPS = {
"platformName": "Android",
"automationName": "UiAutomator2",
"deviceName": "Android Emulator",
"appPackage": "com.example.app", # ⚠️ 修改为实际包名
"appActivity": ".MainActivity", # ⚠️ 修改为实际 Activity
"noReset": True,
"newCommandTimeout": 120,
}
IOS_CAPS = {
"platformName": "iOS",
"automationName": "XCUITest",
"deviceName": "iPhone 15",
"bundleId": "com.example.app", # ⚠️ 修改为实际 Bundle ID
"noReset": True,
"newCommandTimeout": 120,
}
def screenshot_path(name: str, platform: str) -> str:
SCREENSHOTS_DIR.mkdir(parents=True, exist_ok=True)
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
return str(SCREENSHOTS_DIR / f"{name}_{platform}_{ts}.png")
def run_android_test():
"""Android APP 自动化测试。"""
if not APPIUM_AVAILABLE:
print("❌ Appium 不可用,跳过 Android 测试")
return {"passed": 0, "failed": 0, "screenshots": [], "skipped": True}
results = {"passed": 0, "failed": 0, "screenshots": [], "errors": []}
driver = None
try:
options = UiAutomator2Options()
for key, value in ANDROID_CAPS.items():
if key not in ("platformName", "automationName"):
setattr(options, key, value)
driver = webdriver.Remote(APPIUM_HOST, options=options)
print("✅ Android 设备已连接")
# ── 自动生成测试步骤 ──
# [P0] PLT_BSC_LC_001: 验证"物流公司管理"菜单挂载位置与页面骨架完整
# driver.save_screenshot(screenshot_path('PLT_BSC_LC_001', 'android'))
# [P0] PLT_BSC_LC_002: 验证列表查询条件五类控件齐全且类型正确
# driver.save_screenshot(screenshot_path('PLT_BSC_LC_002', 'android'))
# [P1] PLT_BSC_LC_003: 验证三个文本条件各自模糊匹配且互不串字段
# driver.save_screenshot(screenshot_path('PLT_BSC_LC_003', 'android'))
# [P1] PLT_BSC_LC_004: 验证多条件组合查询结果精确且无结果有提示
# driver.save_screenshot(screenshot_path('PLT_BSC_LC_004', 'android'))
# [P1] PLT_BSC_LC_005: 验证查询后分页归位与重置清空全部条件
# driver.save_screenshot(screenshot_path('PLT_BSC_LC_005', 'android'))
# [P1] PLT_BSC_LC_006: 验证状态筛选"全部/启用/停用"三态逐一过滤准确
# driver.save_screenshot(screenshot_path('PLT_BSC_LC_006', 'android'))
# [P0] PLT_BSC_LC_008: 验证列表十类列完整、顺序正确与特殊展示口径
# driver.save_screenshot(screenshot_path('PLT_BSC_LC_008', 'android'))
results["passed"] += 1
except Exception as exc:
results["failed"] += 1
results["errors"].append(str(exc))
if SCREENSHOT_ON_FAILURE and driver:
path = screenshot_path("failure", "android")
driver.save_screenshot(path)
results["screenshots"].append(path)
finally:
if driver:
driver.quit()
return results
def run_ios_test():
"""iOS APP 自动化测试。"""
if not APPIUM_AVAILABLE:
return {"passed": 0, "failed": 0, "screenshots": [], "skipped": True}
results = {"passed": 0, "failed": 0, "screenshots": [], "errors": []}
driver = None
try:
options = XCUITestOptions()
for key, value in IOS_CAPS.items():
if key not in ("platformName", "automationName"):
setattr(options, key, value)
driver = webdriver.Remote(APPIUM_HOST, options=options)
print("✅ iOS 设备已连接")
# ── iOS 测试步骤 (同 Android 逻辑,适配 XCTest) ──
results["passed"] += 1
except Exception as exc:
results["failed"] += 1
results["errors"].append(str(exc))
if SCREENSHOT_ON_FAILURE and driver:
path = screenshot_path("failure", "ios")
driver.save_screenshot(path)
results["screenshots"].append(path)
finally:
if driver:
driver.quit()
return results
def main():
"""主入口。"""
all_results = {}
for platform in ['android', 'ios']:
print(f"\n📱 启动平台: {platform}")
if platform == "android":
results = run_android_test()
elif platform == "ios":
results = run_ios_test()
else:
continue
all_results[platform] = results
if results.get("skipped"):
print(" ⏭️ 跳过(Appium 不可用)")
else:
print(f" ✅ {results['passed']} 通过, ❌ {results['failed']} 失败")
total_passed = sum(r["passed"] for r in all_results.values())
total_failed = sum(r["failed"] for r in all_results.values())
total_screenshots = sum(len(r["screenshots"]) for r in all_results.values())
print(f"\n🏁 移动端执行完成: 总通过 {total_passed}, 总失败 {total_failed}, 截图 {total_screenshots}")
return all_results
if __name__ == "__main__":
main()
@@ -0,0 +1,144 @@
"""
Agentic QE Fleet — Playwright 自动化测试脚本
需求: 物流公司管理需求
生成时间: 2026-09-29T00:22:25.371572+00:00
目标浏览器: chromium, firefox, webkit
对应测试用例: E:\Desktop\xst_files\test\QaAutomationHub\output\test_cases\物流公司管理需求_测试用例.md
用例数量: 164
"""
import asyncio
from pathlib import Path
from datetime import datetime
from playwright.async_api import async_playwright
SCREENSHOTS_DIR = Path(r"E:\Desktop\xst_files\test\QaAutomationHub\output\screenshots\物流公司管理需求")
SCREENSHOT_ON_FAILURE = True
SCREENSHOT_ON_STEP = False
TIMEOUT = 120000
def screenshot_path(name: str, browser: str) -> str:
"""生成截图路径。"""
SCREENSHOTS_DIR.mkdir(parents=True, exist_ok=True)
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
return str(SCREENSHOTS_DIR / f"{name}_{browser}_{ts}.png")
async def run_test(browser_type: str, browser_name: str):
"""执行单个浏览器的测试。"""
results = {"passed": 0, "failed": 0, "screenshots": [], "errors": []}
async with async_playwright() as p:
browser_launcher = getattr(p, browser_type)
browser = await browser_launcher.launch(headless=True)
context = await browser.new_context(
viewport={"width": 1920, "height": 1080},
locale="zh-CN",
)
page = await context.new_page()
page.set_default_timeout(TIMEOUT)
# ============================================================
# 以下为测试用例骨架,请根据实际测试环境配置 BASE_URL 和测试数据
# ============================================================
BASE_URL = "http://localhost:3000" # ⚠️ 请修改为实际测试环境地址
try:
# ── 测试准备: 登录 ──
# await page.goto(f"{BASE_URL}/login")
# await page.screenshot(path=screenshot_path('01_login', browser_name))
# ── 从测试用例自动生成的测试步骤 ──
# [P0] PLT_BSC_LC_001: 验证"物流公司管理"菜单挂载位置与页面骨架完整
# → 展开左侧菜单"基础信息"
# → 进入"承运管理"子菜单核对新增项
# → 点击"物流公司管理"进入页面
# await page.screenshot(path=screenshot_path('PLT_BSC_LC_001', browser_name))
# [P0] PLT_BSC_LC_002: 验证列表查询条件五类控件齐全且类型正确
# → 核对查询条件区控件构成
# → 在状态下拉中查看选项
# → 打开创建时间控件选择区间
# await page.screenshot(path=screenshot_path('PLT_BSC_LC_002', browser_name))
# [P1] PLT_BSC_LC_003: 验证三个文本条件各自模糊匹配且互不串字段
# → 公司名称输入"测试甲"点查询
# → 清空后统一社会信用代码输入"91530102"点查询
# → 清空后联系方式输入"138"点查询
# await page.screenshot(path=screenshot_path('PLT_BSC_LC_003', browser_name))
# [P1] PLT_BSC_LC_004: 验证多条件组合查询结果精确且无结果有提示
# → 状态选择"停用"+名称输入"保山"+创建时间选择本周范围点查询
# → 核对返回集合与分页总数
# → 追加联系方式条件为不可能命中的值"99999999999"再查询
# await page.screenshot(path=screenshot_path('PLT_BSC_LC_004', browser_name))
# [P1] PLT_BSC_LC_005: 验证查询后分页归位与重置清空全部条件
# → 先翻至第 2 页
# → 输入名称"测试甲"点"查询"
# → 观察页码归位与结果
# await page.screenshot(path=screenshot_path('PLT_BSC_LC_005', browser_name))
# [P1] PLT_BSC_LC_006: 验证状态筛选"全部/启用/停用"三态逐一过滤准确
# → 状态选"全部"点查询,记录结果与总条数
# → 状态切"启用"点查询,核对每行状态列
# → 状态切"停用"点查询,核对每行状态列
# await page.screenshot(path=screenshot_path('PLT_BSC_LC_006', browser_name))
# [P0] PLT_BSC_LC_008: 验证列表十类列完整、顺序正确与特殊展示口径
# → 逐列核对表头与顺序
# → 点击 LC-01 行公司名称超链接
# → 核对 LC-05 行简称码列展示(构造简称码为空的公司更佳)
# await page.screenshot(path=screenshot_path('PLT_BSC_LC_008', browser_name))
# [P1] PLT_BSC_LC_009: 验证列表默认按创建时间倒序且新建记录置顶
# → 首次进入列表记录各行的创建时间序列
# → 点击"重置"后再次核对序列
# → 新增一家公司(名称"云南测试甲物流有限公司"的变体不存在冲突者,如"云南测试排序验证物流有限公司")
# await page.screenshot(path=screenshot_path('PLT_BSC_LC_009', browser_name))
# [P1] PLT_BSC_LC_010: 验证分页默认 20 条/页与每页条数切换正确
# → 进入列表核对默认每页条数与页数
# → 切换每页 10/50/100 各档核对条数与总量
# → 翻至末页核对余数
# await page.screenshot(path=screenshot_path('PLT_BSC_LC_010', browser_name))
results["passed"] += 1
except Exception as exc:
results["failed"] += 1
results["errors"].append(str(exc))
if SCREENSHOT_ON_FAILURE:
path = screenshot_path('failure', browser_name)
await page.screenshot(path=path)
results["screenshots"].append(path)
print(f"📸 失败截图: {path}")
finally:
await browser.close()
return results
async def main():
"""主执行入口。"""
all_results = {}
for browser_type in ['chromium', 'firefox', 'webkit']:
print(f"\n🚀 启动浏览器: {browser_type}")
results = await run_test(browser_type, browser_type)
all_results[browser_type] = results
print(f" ✅ {results['passed']} 通过, ❌ {results['failed']} 失败")
# 汇总
total_passed = sum(r["passed"] for r in all_results.values())
total_failed = sum(r["failed"] for r in all_results.values())
total_screenshots = sum(len(r["screenshots"]) for r in all_results.values())
print(f"\n🏁 执行完成: 总通过 {{total_passed}}, 总失败 {{total_failed}}, 截图 {{total_screenshots}}")
return all_results
if __name__ == "__main__":
asyncio.run(main())