|
|
@@ -0,0 +1,496 @@
|
|
|
+"""
|
|
|
+生成 S1 产销协同 UAT 测试报告(按模板格式)
|
|
|
+"""
|
|
|
+import datetime
|
|
|
+from openpyxl import Workbook
|
|
|
+from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
|
|
|
+from openpyxl.utils import get_column_letter
|
|
|
+
|
|
|
+wb = Workbook()
|
|
|
+
|
|
|
+# ── 样式定义 ──
|
|
|
+thin_border = Border(
|
|
|
+ left=Side(style='thin'), right=Side(style='thin'),
|
|
|
+ top=Side(style='thin'), bottom=Side(style='thin')
|
|
|
+)
|
|
|
+header_font = Font(name='微软雅黑', size=11, bold=True)
|
|
|
+title_font = Font(name='微软雅黑', size=14, bold=True)
|
|
|
+normal_font = Font(name='微软雅黑', size=10)
|
|
|
+small_font = Font(name='微软雅黑', size=9)
|
|
|
+center_align = Alignment(horizontal='center', vertical='center', wrap_text=True)
|
|
|
+left_align = Alignment(horizontal='left', vertical='center', wrap_text=True)
|
|
|
+header_fill = PatternFill(start_color='D9E1F2', end_color='D9E1F2', fill_type='solid')
|
|
|
+light_fill = PatternFill(start_color='F2F2F2', end_color='F2F2F2', fill_type='solid')
|
|
|
+yellow_fill = PatternFill(start_color='FFF2CC', end_color='FFF2CC', fill_type='solid')
|
|
|
+
|
|
|
+
|
|
|
+def apply_border(ws, row, col_start, col_end):
|
|
|
+ for c in range(col_start, col_end + 1):
|
|
|
+ ws.cell(row=row, column=c).border = thin_border
|
|
|
+
|
|
|
+
|
|
|
+def write_merged(ws, row, col_start, col_end, value, font=normal_font, alignment=center_align, fill=None):
|
|
|
+ if col_start != col_end:
|
|
|
+ ws.merge_cells(start_row=row, start_column=col_start, end_row=row, end_column=col_end)
|
|
|
+ cell = ws.cell(row=row, column=col_start, value=value)
|
|
|
+ cell.font = font
|
|
|
+ cell.alignment = alignment
|
|
|
+ if fill:
|
|
|
+ cell.fill = fill
|
|
|
+ for c in range(col_start, col_end + 1):
|
|
|
+ ws.cell(row=row, column=c).border = thin_border
|
|
|
+ if fill:
|
|
|
+ ws.cell(row=row, column=c).fill = fill
|
|
|
+
|
|
|
+
|
|
|
+# ── 场景定义 ──
|
|
|
+scenarios = [
|
|
|
+ {
|
|
|
+ "seq": "1", "code": "1.1",
|
|
|
+ "name": "合同评审",
|
|
|
+ "desc": "合同评审列表的增删改查及审批流程",
|
|
|
+ "cases": [
|
|
|
+ ("1.1-1", "合同评审列表查询",
|
|
|
+ "1.点击合同评审菜单进入列表\n2.输入合同号/客户名称查询\n3.点击重置清空条件",
|
|
|
+ "列表查询",
|
|
|
+ "可按合同号、客户名称、日期范围筛选,列表显示合同号、客户、评审状态、创建时间等字段",
|
|
|
+ "Y", "Y", "销售/计划员", "G20150", "", ""),
|
|
|
+ ("1.1-2", "新建合同评审",
|
|
|
+ "1.点击新建按钮\n2.填写合同信息(合同号、客户、产品等)\n3.点击保存",
|
|
|
+ "新增保存",
|
|
|
+ "保存成功后列表刷新显示新记录,合同号唯一性校验通过",
|
|
|
+ "Y", "Y", "销售/计划员", "G20150", "", ""),
|
|
|
+ ("1.1-3", "合同评审提交审批",
|
|
|
+ "1.选择待提交的合同评审记录\n2.点击提交审批\n3.确认提交",
|
|
|
+ "审批提交",
|
|
|
+ "提交后评审状态变更为审批中,审批流自动创建并通知审批人",
|
|
|
+ "Y", "Y", "销售/计划员", "G20150", "", ""),
|
|
|
+ ("1.1-4", "合同评审编辑/删除",
|
|
|
+ "1.选择一条记录点击编辑\n2.修改合同信息后保存\n3.选择另一条未审批的记录点击删除",
|
|
|
+ "编辑/删除",
|
|
|
+ "编辑后字段值正确更新;删除后列表不再显示该记录;已审批记录不可删除",
|
|
|
+ "Y", "Y", "销售/计划员", "G20150", "", ""),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "seq": "2", "code": "1.2",
|
|
|
+ "name": "产品设计",
|
|
|
+ "desc": "产品设计表单的BOM、工艺路线自动填充及下拉框功能",
|
|
|
+ "cases": [
|
|
|
+ ("1.2-1", "产品设计列表查询",
|
|
|
+ "1.点击产品设计菜单\n2.输入产品编码/名称查询",
|
|
|
+ "列表查询",
|
|
|
+ "可按产品编码、产品名称、设计负责人筛选,列表显示单据号、产品信息、设计周期等",
|
|
|
+ "Y", "Y", "设计员", "G20150", "", ""),
|
|
|
+ ("1.2-2", "新建产品设计-选择产品编码自动填充BOM和工艺",
|
|
|
+ "1.点击新建进入表单\n2.点击产品编码选择框,搜索并选择物料\n3.观察BOM子表和工艺子表",
|
|
|
+ "自动填充",
|
|
|
+ "选择产品编码后,BOM子表自动填入物料清单(含物料编码、名称、用量、工序),工艺子表自动填入工序(含产线、路线编码、工序代码)",
|
|
|
+ "Y", "Y", "设计员", "G20150", "", ""),
|
|
|
+ ("1.2-3", "产品设计BOM子表管理",
|
|
|
+ "1.在BOM子表中新增行\n2.选择子物料编码\n3.修改用量/损耗\n4.删除某行",
|
|
|
+ "BOM子表",
|
|
|
+ "支持增删行,选择物料后自动填入物料名称,用量和固定损耗可编辑,父级物料关系正确",
|
|
|
+ "Y", "Y", "设计员", "G20150", "", ""),
|
|
|
+ ("1.2-4", "产品设计工艺子表-产线下拉框与路线编码",
|
|
|
+ "1.在工艺子表新增行\n2.点击产线列下拉框,搜索并选择产线\n3.在路线编码列手动输入编码",
|
|
|
+ "工艺子表",
|
|
|
+ "产线列显示下拉框,可从LineMaster表远程搜索选择(显示格式:Line|Describe);路线编码支持手动输入",
|
|
|
+ "Y", "Y", "设计员", "G20150", "", ""),
|
|
|
+ ("1.2-5", "产品设计保存/编辑/删除",
|
|
|
+ "1.填写完整信息后点击保存\n2.列表中选择记录点击编辑\n3.选择记录点击删除",
|
|
|
+ "保存/编辑/删除",
|
|
|
+ "保存后列表显示新记录;编辑后字段正确更新;删除后记录移除且关联BOM/工艺子表同步删除",
|
|
|
+ "Y", "Y", "设计员", "G20150", "", ""),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "seq": "3", "code": "1.3",
|
|
|
+ "name": "订单评审",
|
|
|
+ "desc": "订单评审列表的增删改查、审批进度及交期确认",
|
|
|
+ "cases": [
|
|
|
+ ("1.3-1", "订单评审列表查询",
|
|
|
+ "1.点击订单评审菜单\n2.输入订单号/客户/日期查询\n3.点击重置",
|
|
|
+ "列表查询",
|
|
|
+ "可按订单号、客户名称、日期范围筛选;列表显示订单号、客户、订单类型、审批进度、状态、变更次数等",
|
|
|
+ "Y", "Y", "销售/计划员", "G20150", "", ""),
|
|
|
+ ("1.3-2", "订单评审审批进度三态显示",
|
|
|
+ "1.查看列表中审批进度列\n2.观察不同状态记录的标签",
|
|
|
+ "审批进度",
|
|
|
+ "未走审批流的记录显示「未审批」蓝色标签;审批中的显示「审批中」橙色标签;已审批完成的显示「审批完成」绿色标签",
|
|
|
+ "Y", "Y", "销售/计划员", "G20150", "", ""),
|
|
|
+ ("1.3-3", "订单评审新增保存",
|
|
|
+ "1.点击新增按钮\n2.填写订单信息\n3.点击保存",
|
|
|
+ "新增保存",
|
|
|
+ "保存成功后列表刷新可见新记录;订单号唯一;必填字段校验通过",
|
|
|
+ "Y", "Y", "销售/计划员", "G20150", "", ""),
|
|
|
+ ("1.3-4", "订单评审变更管理",
|
|
|
+ "1.选择一条订单点击变更\n2.修改订单内容\n3.保存变更",
|
|
|
+ "变更管理",
|
|
|
+ "变更提交后生成变更记录,变更次数+1;审批流重新发起",
|
|
|
+ "Y", "Y", "销售/计划员", "G20150", "", ""),
|
|
|
+ ("1.3-5", "订单评审-交期确认",
|
|
|
+ "1.选择一条或多条审批完成的订单\n2.点击交期确认按钮\n3.确认操作",
|
|
|
+ "交期确认",
|
|
|
+ "调用外部交期确认接口(不含Authorization头),返回OK表示确认成功;确认后订单状态更新",
|
|
|
+ "Y", "Y", "销售/计划员", "G20150", "", ""),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "seq": "4", "code": "1.4",
|
|
|
+ "name": "订单交付",
|
|
|
+ "desc": "订单交付列表查询与交付状态跟踪",
|
|
|
+ "cases": [
|
|
|
+ ("1.4-1", "订单交付列表查询",
|
|
|
+ "1.点击订单交付菜单\n2.输入订单号/客户/交付状态查询",
|
|
|
+ "列表查询",
|
|
|
+ "可按订单号、客户、交付状态、日期范围筛选;列表显示订单号、客户、计划交付日期、实际交付日期、交付状态",
|
|
|
+ "Y", "Y", "计划员/物流", "G20150", "", ""),
|
|
|
+ ("1.4-2", "订单交付状态跟踪",
|
|
|
+ "1.查看列表中的交付状态列\n2.筛选不同状态的订单",
|
|
|
+ "状态跟踪",
|
|
|
+ "交付状态正确显示(待交付/部分交付/已交付/延迟交付);筛选条件生效",
|
|
|
+ "Y", "Y", "计划员/物流", "G20150", "", ""),
|
|
|
+ ("1.4-3", "订单交付确认操作",
|
|
|
+ "1.选择待交付订单\n2.填写实际交付信息\n3.点击确认交付",
|
|
|
+ "交付确认",
|
|
|
+ "确认后交付状态更新为已交付;实际交付日期记录正确;不可重复确认已交付订单",
|
|
|
+ "Y", "Y", "物流/仓管", "G20150", "", ""),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "seq": "5", "code": "1.5",
|
|
|
+ "name": "订单发货",
|
|
|
+ "desc": "发货单的增删改查、销售单号关联及发货明细管理",
|
|
|
+ "cases": [
|
|
|
+ ("1.5-1", "订单发货列表查询",
|
|
|
+ "1.点击订单发货菜单\n2.输入发货单号/销售单号/客户查询",
|
|
|
+ "列表查询",
|
|
|
+ "可按发货单号、销售单号、客户、日期范围筛选;列表显示发货单号、销售单号、客户、发货日期、状态",
|
|
|
+ "Y", "Y", "物流/仓管", "G20150", "", ""),
|
|
|
+ ("1.5-2", "新建发货单",
|
|
|
+ "1.点击新增\n2.选择销售单号(下拉搜索)\n3.选择客户\n4.填写发货信息",
|
|
|
+ "新增发货",
|
|
|
+ "销售单号下拉框支持远程搜索,回显格式为「BillNo|客户名」;客户下拉框同理;保存后发货单号自动生成(SH+日期+流水号)",
|
|
|
+ "Y", "Y", "物流/仓管", "G20150", "", ""),
|
|
|
+ ("1.5-3", "发货单明细行管理",
|
|
|
+ "1.在明细子表中新增行\n2.填写物料、数量、批次等信息\n3.删除某行",
|
|
|
+ "明细管理",
|
|
|
+ "支持增删行;物料选择后自动填入物料名称;数量、批次可编辑;至少保留一行",
|
|
|
+ "Y", "Y", "物流/仓管", "G20150", "", ""),
|
|
|
+ ("1.5-4", "发货单编辑/删除",
|
|
|
+ "1.选择发货单点击编辑\n2.修改信息后保存\n3.选择未发货单据点击删除",
|
|
|
+ "编辑/删除",
|
|
|
+ "编辑后字段正确更新;删除后列表不再显示;已发货单据不可删除",
|
|
|
+ "Y", "Y", "物流/仓管", "G20150", "", ""),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "seq": "6", "code": "1.6",
|
|
|
+ "name": "工单下达",
|
|
|
+ "desc": "工单池查询与工单下达操作",
|
|
|
+ "cases": [
|
|
|
+ ("1.6-1", "工单下达列表查询",
|
|
|
+ "1.点击工单下达菜单\n2.输入工单号/物料/产线查询",
|
|
|
+ "列表查询",
|
|
|
+ "可按工单号、物料编码、产线、日期范围筛选;列表显示工单号、物料、数量、产线、状态",
|
|
|
+ "Y", "Y", "计划员/调度", "G20150", "", ""),
|
|
|
+ ("1.6-2", "工单选择与下达",
|
|
|
+ "1.勾选待下达工单\n2.点击下达按钮\n3.确认下达",
|
|
|
+ "工单下达",
|
|
|
+ "下达后工单状态变更;已下达工单不可重复下达;下达后MES可见",
|
|
|
+ "Y", "Y", "计划员/调度", "G20150", "", ""),
|
|
|
+ ("1.6-3", "工单状态跟踪",
|
|
|
+ "1.查看工单列表中状态列\n2.筛选不同状态工单",
|
|
|
+ "状态跟踪",
|
|
|
+ "工单状态正确显示(待下达/已下达/生产中/已完成/已关闭);筛选条件生效",
|
|
|
+ "Y", "Y", "计划员/调度", "G20150", "", ""),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "seq": "7", "code": "1.7",
|
|
|
+ "name": "产销协同指标看板",
|
|
|
+ "desc": "S1看板的指标展示、筛选与下钻分析",
|
|
|
+ "cases": [
|
|
|
+ ("1.7-1", "产销协同指标看板-指标展示",
|
|
|
+ "1.点击产销协同指标看板菜单\n2.观察页面显示的L1指标卡片",
|
|
|
+ "看板展示",
|
|
|
+ "显示订单及时交付率、订单交付周期、成品库存周转天数等L1指标卡片;每张卡片展示当前值、目标值、偏差和红黄绿状态",
|
|
|
+ "Y", "Y", "管理层/计划员", "G20150", "", ""),
|
|
|
+ ("1.7-2", "产销协同指标看板-筛选与下钻",
|
|
|
+ "1.点击某张L1指标卡片\n2.观察下方L2指标与趋势图\n3.输入客户名称筛选",
|
|
|
+ "下钻分析",
|
|
|
+ "点击L1卡片后下方展示对应的L2指标和趋势图;客户筛选条件对图表数据生效",
|
|
|
+ "Y", "Y", "管理层/计划员", "G20150", "", ""),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "seq": "8", "code": "1.8",
|
|
|
+ "name": "需求明细核验",
|
|
|
+ "desc": "需求明细列表查询与核验操作",
|
|
|
+ "cases": [
|
|
|
+ ("1.8-1", "需求明细列表查询",
|
|
|
+ "1.点击需求明细核验菜单\n2.输入工单号/物料/日期查询",
|
|
|
+ "列表查询",
|
|
|
+ "可按工单号、物料编码、需求日期筛选;列表显示工单号、物料、需求数量、需求日期、核验状态",
|
|
|
+ "Y", "Y", "计划员", "G20150", "", ""),
|
|
|
+ ("1.8-2", "需求核验操作",
|
|
|
+ "1.勾选待核验的记录\n2.点击核验确认\n3.填写核验意见",
|
|
|
+ "需求核验",
|
|
|
+ "核验后状态更新为已核验;核验意见保存正确;可批量核验",
|
|
|
+ "Y", "Y", "计划员", "G20150", "", ""),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "seq": "9", "code": "1.9",
|
|
|
+ "name": "计划联动看板",
|
|
|
+ "desc": "联动计划的增删改查与联动关系管理",
|
|
|
+ "cases": [
|
|
|
+ ("1.9-1", "计划联动看板列表查询",
|
|
|
+ "1.点击计划联动看板菜单\n2.输入计划编号/来源单号查询",
|
|
|
+ "列表查询",
|
|
|
+ "可按计划编号、来源单号、计划类型筛选;列表显示计划编号、来源类型、目标类型、创建时间",
|
|
|
+ "Y", "Y", "计划员", "G20150", "", ""),
|
|
|
+ ("1.9-2", "联动计划创建/编辑",
|
|
|
+ "1.点击新增创建联动计划\n2.选择来源单据和目标单据\n3.保存联动关系",
|
|
|
+ "创建/编辑",
|
|
|
+ "保存后列表显示新联动计划;来源和目标关系正确建立;编辑后可修改联动配置",
|
|
|
+ "Y", "Y", "计划员", "G20150", "", ""),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+]
|
|
|
+
|
|
|
+# ═══════════════════════════════════════════
|
|
|
+# Sheet 0: 目录
|
|
|
+# ═══════════════════════════════════════════
|
|
|
+ws_dir = wb.active
|
|
|
+ws_dir.title = "目录"
|
|
|
+
|
|
|
+# 列宽
|
|
|
+for i, w in enumerate([6, 18, 18, 18, 18, 18, 18], 1):
|
|
|
+ ws_dir.column_dimensions[get_column_letter(i)].width = w
|
|
|
+
|
|
|
+row = 1
|
|
|
+title_labels = ["生产管理业务场景目录"] * 6
|
|
|
+for ci in range(1, 7):
|
|
|
+ ws_dir.cell(row=row, column=ci, value=title_labels[ci-1]).font = title_font
|
|
|
+ ws_dir.cell(row=row, column=ci).alignment = center_align
|
|
|
+ ws_dir.merge_cells(start_row=row, start_column=1, end_row=row, end_column=6)
|
|
|
+row += 1
|
|
|
+
|
|
|
+dir_headers = ["序号", "测试分场景", "测试分场景", "测试分场景", "计划完成时间", "责任人"]
|
|
|
+for ci, h in enumerate(dir_headers, 1):
|
|
|
+ ws_dir.cell(row=row, column=ci, value=h).font = header_font
|
|
|
+ ws_dir.cell(row=row, column=ci).alignment = center_align
|
|
|
+ ws_dir.cell(row=row, column=ci).fill = header_fill
|
|
|
+ apply_border(ws_dir, row, ci, ci)
|
|
|
+row += 1
|
|
|
+
|
|
|
+for s in scenarios:
|
|
|
+ ws_dir.cell(row=row, column=1, value=int(s["seq"])).font = normal_font
|
|
|
+ ws_dir.cell(row=row, column=1).alignment = center_align
|
|
|
+ write_merged(ws_dir, row, 2, 4, s["name"], normal_font, center_align)
|
|
|
+ ws_dir.cell(row=row, column=5, value="2026/6/3-6").font = normal_font
|
|
|
+ ws_dir.cell(row=row, column=5).alignment = center_align
|
|
|
+ ws_dir.cell(row=row, column=6, value="张苗苗、王远航").font = normal_font
|
|
|
+ ws_dir.cell(row=row, column=6).alignment = center_align
|
|
|
+ for c in range(1, 7):
|
|
|
+ apply_border(ws_dir, row, c, c)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+# 测试要求
|
|
|
+row += 1
|
|
|
+req_lines = [
|
|
|
+ "测试要求:",
|
|
|
+ "1. 请根据S1产销协同功能设计文档撰写测试场景。",
|
|
|
+ "2. 每场景不少于2张单据,每单行数不小于2行。",
|
|
|
+]
|
|
|
+for line in req_lines:
|
|
|
+ write_merged(ws_dir, row, 1, 6, line, small_font, left_align)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+row += 1
|
|
|
+info_lines = [
|
|
|
+ "测试账号:",
|
|
|
+ "1.Web地址: http://172.16.8.154:8020/",
|
|
|
+ "2.账号: G20150 密码: 111",
|
|
|
+ "3.库存组织:8010",
|
|
|
+]
|
|
|
+for line in info_lines:
|
|
|
+ write_merged(ws_dir, row, 1, 6, line, small_font, left_align)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+row += 1
|
|
|
+write_merged(ws_dir, row, 1, 6, "测试人所属部门:", small_font, left_align)
|
|
|
+row += 1
|
|
|
+write_merged(ws_dir, row, 1, 6, "测试结果:合格/不合格", small_font, left_align)
|
|
|
+row += 1
|
|
|
+write_merged(ws_dir, row, 1, 2, "测试人姓名:", small_font, center_align)
|
|
|
+write_merged(ws_dir, row, 3, 4, "负责顾问:", small_font, center_align)
|
|
|
+
|
|
|
+
|
|
|
+# ═══════════════════════════════════════════
|
|
|
+# 各场景 Sheet
|
|
|
+# ═══════════════════════════════════════════
|
|
|
+COLS = 17 # A-Q
|
|
|
+
|
|
|
+for s in scenarios:
|
|
|
+ ws = wb.create_sheet(title=f"{s['seq']} {s['name']}")
|
|
|
+
|
|
|
+ # 列宽
|
|
|
+ widths = [8, 8, 18, 18, 18, 18, 12, 12, 18, 18, 18, 18, 18, 8, 8, 12, 14, 22]
|
|
|
+ for i, w in enumerate(widths, 1):
|
|
|
+ ws.column_dimensions[get_column_letter(i)].width = w
|
|
|
+
|
|
|
+ row = 1
|
|
|
+
|
|
|
+ # ─ 第一行:详细测试结果(占据A-J列的一部分)─
|
|
|
+ for ci in range(1, 11):
|
|
|
+ ws.cell(row=row, column=ci).border = thin_border
|
|
|
+ write_merged(ws, row, 1, 5, "详细测试结果", header_font, center_align, header_fill)
|
|
|
+ for ci in range(6, 11):
|
|
|
+ ws.cell(row=row, column=ci).fill = header_fill
|
|
|
+ write_merged(ws, row, 6, 7, "第一轮测试\n第一轮测试", header_font, center_align, header_fill)
|
|
|
+ write_merged(ws, row, 8, 9, "第二轮测试\n第二轮测试", header_font, center_align, header_fill)
|
|
|
+ # 空白填充
|
|
|
+ write_merged(ws, row, 10, 10, "", normal_font, center_align, header_fill)
|
|
|
+ write_merged(ws, row, 11, 13, "测试内容", header_font, center_align, header_fill)
|
|
|
+ write_merged(ws, row, 14, 14, "流程编码", header_font, center_align, header_fill)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+ # ─ 第二行:计数 ─
|
|
|
+ write_merged(ws, row, 1, 5, "计数", normal_font, center_align, light_fill)
|
|
|
+ write_merged(ws, row, 6, 7, "第一轮测试", normal_font, center_align, light_fill)
|
|
|
+ write_merged(ws, row, 8, 9, "第二轮测试", normal_font, center_align, light_fill)
|
|
|
+ write_merged(ws, row, 10, 10, "", normal_font, center_align, light_fill)
|
|
|
+ write_merged(ws, row, 11, 13, s["name"], normal_font, center_align, yellow_fill)
|
|
|
+ write_merged(ws, row, 14, 17, s["code"], normal_font, center_align, yellow_fill)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+ # ─ 第三行:测试人 ─
|
|
|
+ write_merged(ws, row, 1, 5, "测试人", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 6, 7, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 8, 9, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 10, 10, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 11, 13, s["name"], normal_font, center_align, yellow_fill)
|
|
|
+ write_merged(ws, row, 14, 17, s["code"], normal_font, center_align, yellow_fill)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+ # ─ 第四行:测试日期 ─
|
|
|
+ write_merged(ws, row, 1, 5, "测试日期", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 6, 7, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 8, 9, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 10, 10, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 11, 13, s["name"], normal_font, center_align, yellow_fill)
|
|
|
+ write_merged(ws, row, 14, 17, s["code"], normal_font, center_align, yellow_fill)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+ # ─ 缺陷行 ─
|
|
|
+ defect_types = [("缺陷", "高(H)"), ("缺陷", "中(M)"), ("缺陷", "低(L)")]
|
|
|
+ for dt_label, dt_val in defect_types:
|
|
|
+ write_merged(ws, row, 1, 5, dt_label, normal_font, center_align)
|
|
|
+ write_merged(ws, row, 6, 7, dt_val, normal_font, center_align)
|
|
|
+ write_merged(ws, row, 8, 9, dt_val, normal_font, center_align)
|
|
|
+ write_merged(ws, row, 10, 10, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 11, 13, "编写人", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 14, 17, "", normal_font, center_align)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+ # ─ 更新人/更新日期行 ─
|
|
|
+ write_merged(ws, row, 1, 5, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 6, 7, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 8, 9, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 10, 10, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 11, 13, "更新人", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 14, 17, "", normal_font, center_align)
|
|
|
+ row += 1
|
|
|
+ write_merged(ws, row, 1, 5, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 6, 7, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 8, 9, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 10, 10, "", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 11, 13, "更新日期", normal_font, center_align)
|
|
|
+ write_merged(ws, row, 14, 17, "", normal_font, center_align)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+ # ─ 表头行 ─
|
|
|
+ header_row = row
|
|
|
+ col_headers = [
|
|
|
+ ("用例编号", 1, 2),
|
|
|
+ ("测试内容", 3, 4),
|
|
|
+ ("测试步骤", 5, 7),
|
|
|
+ ("系统功能", 8, 9),
|
|
|
+ ("预期结果", 10, 14),
|
|
|
+ ("测试结果\n(Y/H/M/L)", 15, 16),
|
|
|
+ ("角色", 17, 17),
|
|
|
+ # Extra columns for login/user/doc/remark
|
|
|
+ ]
|
|
|
+ hdr_map = [
|
|
|
+ (1, 2, "用例编号"), (3, 4, "测试内容"), (5, 7, "测试步骤"),
|
|
|
+ (8, 9, "系统功能"), (10, 14, "预期结果"), (15, 16, "测试结果\n(Y/H/M/L)"),
|
|
|
+ (17, 17, "角色"),
|
|
|
+ ]
|
|
|
+ for cs, ce, htxt in hdr_map:
|
|
|
+ write_merged(ws, row, cs, ce, htxt, header_font, center_align, header_fill)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+ # 子表头行
|
|
|
+ sub_hdrs = [
|
|
|
+ (1, 2, "用例编号"),
|
|
|
+ (3, 4, "测试内容"),
|
|
|
+ (5, 7, "测试步骤"),
|
|
|
+ (8, 9, "系统功能"),
|
|
|
+ (10, 14, "预期结果"),
|
|
|
+ (15, 15, "1st"),
|
|
|
+ (16, 16, "2nd"),
|
|
|
+ (17, 17, "角色"),
|
|
|
+ ]
|
|
|
+ # 写第二次表头(预期结果等小标题)- 用扩展列
|
|
|
+ write_merged(ws, row, 1, 2, "用例编号", header_font, center_align, header_fill)
|
|
|
+ write_merged(ws, row, 3, 4, "测试内容", header_font, center_align, header_fill)
|
|
|
+ write_merged(ws, row, 5, 7, "测试步骤", header_font, center_align, header_fill)
|
|
|
+ write_merged(ws, row, 8, 9, "系统功能", header_font, center_align, header_fill)
|
|
|
+ write_merged(ws, row, 10, 14, "预期结果", header_font, center_align, header_fill)
|
|
|
+ write_merged(ws, row, 15, 15, "1st", header_font, center_align, header_fill)
|
|
|
+ write_merged(ws, row, 16, 16, "2nd", header_font, center_align, header_fill)
|
|
|
+ write_merged(ws, row, 17, 17, "角色", header_font, center_align, header_fill)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+ # ─ 测试用例数据行 ─
|
|
|
+ for tc in s["cases"]:
|
|
|
+ case_id, content, steps, func, expected, r1, r2, role, user, doc, remark = tc
|
|
|
+ write_merged(ws, row, 1, 2, case_id, normal_font, center_align)
|
|
|
+ write_merged(ws, row, 3, 4, content, normal_font, left_align)
|
|
|
+ write_merged(ws, row, 5, 7, steps, normal_font, left_align)
|
|
|
+ write_merged(ws, row, 8, 9, func, normal_font, center_align)
|
|
|
+ write_merged(ws, row, 10, 14, expected, normal_font, left_align)
|
|
|
+ ws.cell(row=row, column=15, value=r1).font = normal_font
|
|
|
+ ws.cell(row=row, column=15).alignment = center_align
|
|
|
+ ws.cell(row=row, column=15).border = thin_border
|
|
|
+ ws.cell(row=row, column=16, value=r2).font = normal_font
|
|
|
+ ws.cell(row=row, column=16).alignment = center_align
|
|
|
+ ws.cell(row=row, column=16).border = thin_border
|
|
|
+ ws.cell(row=row, column=17, value=role).font = normal_font
|
|
|
+ ws.cell(row=row, column=17).alignment = center_align
|
|
|
+ ws.cell(row=row, column=17).border = thin_border
|
|
|
+ # 设置行高
|
|
|
+ ws.row_dimensions[row].height = max(45, steps.count('\n') * 15 + 30)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+ # ─ 图例行 ─
|
|
|
+ row += 1
|
|
|
+ legend_lines = [
|
|
|
+ "Y : 实际结果和预期结果一致",
|
|
|
+ "H : 严重缺陷(系统崩溃/错误数据影响其他流程等)",
|
|
|
+ "M : 中等程度缺陷(还能用/有错误数据但不影响其他的流程等)",
|
|
|
+ "L : 低程度缺陷(设计/错误消息/菜单选项/错误警告/帮助问题等)",
|
|
|
+ "- : 不属于测试范围",
|
|
|
+ ]
|
|
|
+ for line in legend_lines:
|
|
|
+ write_merged(ws, row, 1, 10, line, small_font, left_align)
|
|
|
+ row += 1
|
|
|
+
|
|
|
+
|
|
|
+# ── 保存 ──
|
|
|
+output_path = r"d:\DEMONET\doc\S1产销协同_UAT测试报告v1.0.xlsx"
|
|
|
+wb.save(output_path)
|
|
|
+print(f"✅ 测试报告已生成: {output_path}")
|