---
URL: "/zh-CN/gallery/bpp_test.html"
LLMS_URL: "/zh-CN/gallery/bpp_test.md"
layout: "doc"
recommended: true
pageClass: "gallery-page-class"
title: "无锡硕放机场个性化登机牌"
---

---
layout: doc
# 开启推荐
recommended: true
pageClass: gallery-page-class
title: 无锡硕放机场个性化登机牌
---

# 登机牌打印拦截系统 综合测试用例文档

> **配置说明**：本版本帧边界统一为 `StartMarker = "\u0002"` (STX)，`EndMarker = "\u0003"` (ETX)。  
> 所有测试数据均以 `\x02` 开头、`\x03` 结尾，文档中以可读形式 `[STX]...数据...[ETX]` 表示，实际测试时需发送对应十六进制字节。


## 1. 文档概述

- **测试目标**：验证 `AirlinePrintInterceptor` 服务在 STX/ETX 帧封装下的功能正确性、稳定性和兼容性。
- **核心特性**：
  - 接收端：轮询缓冲区，基于 `EndMarker` (ETX) 提取完整帧，`StartMarker` (STX) 用于定位帧头（可选空）。
  - 协议处理：标识符为 `#` + 两位数字，支持多触发组、透传前缀、重复标识符替换、内容长度补齐。
  - 输出封装：自动在数据前后添加 STX 和 ETX（可配置，防重复）。
  - SET Mode 双向通信：发送 `SET Mode` 或 `SM;` 命令后，等待打印机响应并回传源端，同时过滤回传帧防止循环。
  - AEA 状态查询（可关闭）、Polly 重试、看门狗复位。
- **数据流向**：

```mermaid
flowchart LR
    %% 外部设备
    subgraph 外部设备
        A[["串口调试助手 (COM4)"]]:::source
    end

    %% 虚拟串口对
    subgraph 虚拟串口对
        B[["COM4 ↔ COM5 虚拟串口对"]]:::virtual
    end

    %% 服务内部处理
    subgraph AirlinePrintInterceptor 服务
        subgraph 串口读取与帧缓冲
            C["轮询读取源串口 (COM5)"]:::service
            D["内存帧缓冲区 (MemoryStream)"]:::service
            E["根据 EndMarker ($) 提取完整帧"]:::service
        end

        subgraph 数据处理
            F["StringMessageProcessor 协议处理"]:::process
        end

        subgraph 输出与监控
            G["输出帧封装 (添加 STX/ETX)"]:::service
            H["写入目标串口 (COM1)"]:::service
            I["打印机状态查询 (DLE EOT)"]:::monitor
            J["看门狗定时器"]:::monitor
            K["命名管道日志服务"]:::monitor
        end
    end

    %% 打印机
    L["打印机 (COM1)"]:::printer

    %% WPF客户端
    M["WPF 监控客户端"]:::client

    %% 流程连线
    A -- 发送原始数据 ([STX]CP#...$[ETX]) --> B
    B -- 数据到达 COM5 --> C
    C -- 每次读取的字节块 --> D
    D -- 缓冲数据 --> E
    E -- 完整数据帧 --> F
    F -- 处理后的数据 --> G
    G -- 添加控制字符后的帧 --> H
    H -- 最终数据 --> L

    F -.-> I
    J -.-> E
    F -.-> K
    K -.-> M

    %% 样式定义
    classDef source fill:#e6f3ff,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a;
    classDef virtual fill:#f0fdf4,stroke:#22c55e,stroke-width:2px,color:#166534;
    classDef service fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#92400e;
    classDef process fill:#ede9fe,stroke:#8b5cf6,stroke-width:2px,color:#5b21b6;
    classDef monitor fill:#fce7f3,stroke:#ec4899,stroke-width:2px,color:#9d174d;
    classDef printer fill:#e0e7ff,stroke:#6366f1,stroke-width:2px,color:#3730a3;
    classDef client fill:#d1fae5,stroke:#10b981,stroke-width:2px,color:#064e3b;
```

- **测试环境**：Windows 7/10/11，com0com 虚拟串口。

## 2. 帧接收与切分测试

### TC‑FR‑01 单个 `[ETX]` 结尾的帧正确提取

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑FR‑01 |
| **测试目的** | 验证使用 `ETX` 作为结束标记时，轮询线程能从串口数据流中提取完整帧。 |
| **前置条件** | 1. `SerialPort` 配置：`StartMarker = "\u0002"`，`EndMarker = "\u0003"`<br>2. 服务已启动，源端口 `COM5` 已打开<br>3. 虚拟串口对 `COM4 ↔ COM5` 已创建<br>4. 串口调试助手连接 `COM4`（以十六进制发送） |
| **测试步骤** | 从 `COM4` 发送十六进制：`02 43 50 23 30 31 43 30 31 23 30 31 56 23 30 35 48 65 6C 6C 6F 23 03 10`<br>（对应文本：`[STX]CP#01C01#01V#05Hello#[ETX]`） |
| **预期结果** | 1. 服务日志输出“本轮提取到 1 个完整帧”<br>2. 帧内容为完整的 `[STX]CP#01C01#01V#05Hello#[ETX]`<br>3. `StringMessageProcessor` 正常接收该帧（若满足触发标识） |

### TC‑FR‑02 连续两帧按 `[ETX]` 分离

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑FR‑02 |
| **测试目的** | 多个帧合并到达时能根据 `ETX` 正确切分。 |
| **前置条件** | 同 TC‑FR‑01 |
| **测试步骤** | 发送十六进制：`02 43 50 23 30 31 23 41 23 03 10 02 43 50 23 30 32 23 42 23 03 10`<br>（即 `[STX]CP#01#A#[ETX][STX]CP#02#B#[ETX]`） |
| **预期结果** | 提取两帧：`[STX]CP#01#A#[ETX]` 和 `[STX]CP#02#B#[ETX]`，分别处理 |

### TC‑FR‑03 无 `[ETX]` 结尾时不提取，看门狗超时后重置

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑FR‑03 |
| **测试目的** | 不完整帧不提取，长时间无数据后看门狗复位串口。 |
| **前置条件** | 同 TC‑FR‑01，看门狗超时 30 秒 |
| **测试步骤** | 1. 发送 `[STX]CP#01#A#`（无结尾）<br>2. 35 秒内不发送任何数据 |
| **预期结果** | 1. 数据保留在缓冲区不处理<br>2. 约 30 秒后日志“看门狗超时…准备重启串口”<br>3. 串口被重置，恢复等待状态 |

### TC‑FR‑04 起始标记为空，直接从缓冲区头部查找 `[ETX]`

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑FR‑04 |
| **测试目的** | `StartMarker` 为空时，系统从缓冲区起始位置直接查找结束标记切分帧。 |
| **前置条件** | `SerialPort` 配置：`StartMarker = ""`，`EndMarker = "\u0003"` |
| **测试步骤** | 发送十六进制：`41 41 42 42 03 10 43 43 44 44 03 10`（对应 `AABB[ETX]CCDD[ETX]`） |
| **预期结果** | 提取两帧：`AABB[ETX]` 和 `CCDD[ETX]` |


## 3. 协议处理模块测试 (`StringMessageProcessor`)

### 3.1 触发标识匹配（分组模型）

#### TC‑TR‑01 单个触发组匹配成功

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑TR‑01 |
| **测试目的** | 配置单个触发组，数据包含对应标识时触发规则处理。 |
| **前置条件** | 组1：`TriggerIdentifier = "#88"`，规则：替换 `#05` → `"WANG"` |
| **测试步骤** | 发送帧 `[STX]CP#01C01#01V#88#05Hello#[ETX]` |
| **预期结果** | 1. 日志输出“找到触发标识字段 #88”<br>2. 处理后数据为 `[STX]CP#01C01#01V#88#05WANG#[ETX]` |

#### TC‑TR‑02 内容中的子串不触发（严格字段匹配）

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑TR‑02 |
| **测试目的** | 标识符必须为独立字段 `#88`，内容中的 `88` 不触发。 |
| **前置条件** | 组1：`TriggerIdentifier = "#88"` |
| **测试步骤** | 发送帧 `[STX]CP#01C01#01V#05Test88#[ETX]` |
| **预期结果** | 日志“未匹配任何触发标识，原样转发”，数据不变 |

#### TC‑TR‑03 多个触发组分别生效

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑TR‑03 |
| **测试目的** | 不同触发组对应不同规则集，互不干扰。 |
| **前置条件** | 组1：`#88` → 替换 `#05` → `"A"`<br>组2：`#99` → 替换 `#07` → `"B"` |
| **测试步骤** | 分别发送含 `#88` 和 `#99` 的帧 |
| **预期结果** | `#88` 帧只替换 `#05` 为 `A`，`#99` 帧只替换 `#07` 为 `B` |

### 3.2 替换与插入规则

#### TC‑RPI‑01 目标字段存在，替换所有重复项

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑RPI‑01 |
| **测试目的** | 数据中存在多个相同标识符时，全部替换。 |
| **前置条件** | 规则：`TargetIdentifier = "#44"`，`CustomContent = "NEW"` |
| **测试步骤** | 发送 `[STX]CP#01C01#01V#44Old#44Old#[ETX]` |
| **预期结果** | 输出 `[STX]CP#01C01#01V#44NEW#44NEW#[ETX]`，日志“已替换 2 个 #44” |

#### TC‑RPI‑02 目标字段不存在，插入到合适位置

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑RPI‑02 |
| **测试目的** | 目标不存在时，在小于参考值的最大标识符后插入新字段。 |
| **前置条件** | 规则：`TargetIdentifier = "#23"`，`CustomContent = "VIP"` |
| **测试步骤** | 发送 `[STX]CP#01C01#01V#05Zhang#07Li#[ETX]` |
| **预期结果** | 在 `#07` 后插入 `#23VIP`，结果为 `[STX]CP#01C01#01V#05Zhang#07Li#23VIP#[ETX]` |

### 3.3 内容长度补齐

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑PAD‑01 |
| **测试目的** | 内容长度不足时尾部补空格。 |
| **前置条件** | 规则：`TargetIdentifier = "#05"`，`CustomContent = "Hi"`，`ContentLength = 10` |
| **测试步骤** | 发送 `[STX]CP#01C01#01V#05Test#[ETX]` |
| **预期结果** | 输出 `[STX]CP#01C01#01V#05Hi       #[ETX]`（8个空格），日志显示长度10 |

### 3.4 透传控制帧

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑PS‑01 |
| **测试目的** | 匹配透传前缀的控制帧直接转发，不修改。 |
| **前置条件** | `PassthroughIdentifiers = ["WS", "MX", "EP#"]` |
| **测试步骤** | 分别发送 `[STX]WS...[ETX]`、`[STX]MX...[ETX]`、`[STX]EP#...[ETX]` |
| **预期结果** | 日志“透传前缀匹配 'WS'”（示例），数据原样返回，不触发规则 |


## 4. 输出帧封装测试

### TC‑WRP‑01 写入打印机前自动添加 STX/ETX

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑WRP‑01 |
| **测试目的** | 启用输出封装后，数据自动包裹 STX 和 ETX。 |
| **前置条件** | `EnableOutputFrameWrapping = true`，`OutputStartMarker = "\u0002"`，`OutputEndMarker = "\u0003"` |
| **测试步骤** | 处理一帧 `CP#01#A#$`（内部数据，无控制符），观察 COM1 输出字节 |
| **预期结果** | COM1 收到 `02 43 50 23 30 31 23 41 23 03 10`，日志显示添加帧头/帧尾 |

### TC‑WRP‑02 已含标记时不重复添加

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑WRP‑02 |
| **测试目的** | 若处理器输出已包含 STX/ETX，直接发送，避免重复封装。 |
| **前置条件** | 同上，模拟处理器输出 `[STX]CP#01#A#[ETX]` |
| **测试步骤** | 直接写入该数据 |
| **预期结果** | 日志“无需重复封装”，发送字节与输入一致 |


## 5. SET Mode 双向通信测试

### TC‑SET‑01 命令触发打印机响应并回传

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑SET‑01 |
| **测试目的** | 发送包含 `SET Mode` 的命令后，等待打印机响应并回写到源串口。 |
| **前置条件** | `SetModeCommands = ["SET Mode", "SM;"]`，打印机正常连接 COM1 |
| **测试步骤** | 发送 `[STX]SM;A;999;01[ETX]` |
| **预期结果** | 1. 打印机返回响应（如 `SR;0;A;999`）<br>2. 响应被封装为 `[STX]SR;0;A;999[ETX]` 写入 COM5，从而返回 COM4<br>3. 回传数据指纹被记录，后续轮询时自动丢弃 |

### TC‑SET‑02 回传帧防循环

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑SET‑02 |
| **测试目的** | 刚回传到源端的数据再次被轮询读取时，自动丢弃。 |
| **前置条件** | 已完成一次 SET Mode 响应回传 |
| **测试步骤** | 回传数据再次出现在 COM5 缓冲区（模拟） |
| **预期结果** | 日志“回传帧过滤：丢弃已回传数据”，数据不进入处理流程 |


## 6. 配置校验测试（启动时）

### TC‑VAL‑01 必填字段缺失导致启动中止

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑VAL‑01 |
| **测试目的** | `SourcePort` 为空时服务拒绝启动。 |
| **前置条件** | 配置 `"SourcePort": ""` |
| **测试步骤** | 启动服务 |
| **预期结果** | 日志“[配置错误] SerialPort.SourcePort 不能为空”，服务停止 |

### TC‑VAL‑02 规则中目标标识符为空时报错

| 项目 | 内容 |
|------|------|
| **用例编号** | TC‑VAL‑02 |
| **测试目的** | 规则必须指定 `TargetIdentifier`。 |
| **前置条件** | 某条规则 `TargetIdentifier = ""` |
| **测试步骤** | 启动服务 |
| **预期结果** | 日志“Rules[0].TargetIdentifier 不能为空”，启动中止 |


**文档版本**：v4.1  
**最后更新**：2026-05-26  
**重要提醒**：由于帧边界为不可见控制字符，测试时请使用十六进制发送工具，确保正确插入 `02`（STX）和 `03`（ETX）。
