front/docs/订单全链路自动化测试方案.md
zzh 5191d1981f feat: 仓储模块前端、菜单同步扩展及相关页面优化
新增仓储模块页面与 API、店铺授权/店铺订单页面及路由权限目录;
扩展菜单管理同步能力支持二级子菜单与三级按钮;优化公告、仓库地址、下单等页面。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 15:19:35 +08:00

21 KiB
Raw Permalink Blame History

订单全链路自动化测试方案

版本:v1.0
日期:2026-07-08
适用范围:OMS 订单从创建 → 预报 → 入库 → 支付 → 出库 → 轨迹 → 签收(设计态)
关联文档:oms系统设计-050801.md §4、§6、§10.3;物流下单协议.md;订单批量处理与异步队列方案0707.md


1. 目标与范围

1.1 目标

建立一套可重复执行、可接入 CI 的自动化测试流程,覆盖订单主 happy path:

下单预报 → 入库收货 → 客户支付 → 出库发货 → 轨迹同步 → 签收完成

并验证各阶段:

  • 订单状态(OrderStatus)与时间字段(ReceiveTime / PayTime / ShipTime / SignTime)
  • 费用(预报 / 入库 / 出库阶段 t_order_fee)
  • 客户余额与流水(t_customer.Balance、t_customer_account_flow)
  • 仓储操作记录(t_inbound_record / t_outbound_record)
  • 轨迹服务联动(UpsertSmallBag,可 mock)
  • 权限与数据范围(客户只能看到自己的订单)

1.2 当前实现边界(必读)

阶段 状态码 后端是否已实现 自动化策略
小包创建 + 预报计费 predeclared ✅ API 断言
入库扫描 pendingPayment ✅ API 断言
支付 pendingShip ✅ API + 余额断言
出库扫描 pendingOnline ✅ API 断言
运输中 shipping ❌ 无写入逻辑 Phase 2:mock 轨迹回调或手工 DB 置态
派送成功(签收) deliverySuccess + SignTime ❌ 无写入逻辑 Phase 2:同上;或 Track 服务 UpdateOrderStatus
问题件 / 理赔件 problematic / claimed ✅ 分支用例

结论:Phase 1 自动化覆盖到 pendingOnline(待上网) 为「OMS 内闭环」;签收段在 OMS 回写接口落地前,用 Track 侧断言 + 预留 OMS 状态同步测试桩 衔接。


2. 测试分层架构

flowchart TB
    subgraph L4["L4 可选 UI E2E"]
        UI[Playwright / Cypress<br/>关键页面冒烟]
    end

    subgraph L3["L3 API 全链路 E2E(推荐主战场)"]
        E2E[OrderLifecycleE2ETests<br/>真实 MySQL + TestServer]
    end

    subgraph L2["L2 API 集成"]
        INT[SimpleAdmin.Api.IntegrationTests<br/>路由注册 + Mock 依赖]
    end

    subgraph L1["L1 单元测试"]
        UNIT[Oms.Tests<br/>计费 / 签名 / Batch 治理]
    end

  L1 --> L2 --> L3
  L3 -.-> L4
层级 项目位置 依赖 运行频率
L1 单元 oms0414-back/src/Oms.Tests 无 DB 每次 PR
L2 集成 oms0414-back/src/SimpleAdmin.Api.IntegrationTests TestServer + 内存 RBAC 每次 PR
L3 API E2E 待建 Oms.E2E.Tests 或扩展现有 IntegrationTests Docker MySQL + 可选 RabbitMQ/WireMock 每日 / 合并前
L4 UI E2E 待建 oms0414/e2e/ 前端 dev + 后端 API 发版前手动 / 夜间

3. 测试环境与配置

3.1 基础服务

组件 用途 本地 / CI 建议
MySQL 8.x 业务库 oms_test docker compose 独立库,每次 E2E 前 migrate
SimpleAdmin.Api OMS 后端 ASPNETCORE_ENVIRONMENT=Testing
前端 Vite UI E2E 可选 localhost:5173
RabbitMQ 批量任务 E2E 默认 关闭;批量专项用例单独 job 开启
WireMock / MockServer Track、itfx 下游 E2E 默认 mock,避免外网依赖

3.2 后端配置项(appsettings.Testing.json 或环境变量)

{
  "ConnectionStrings": { "Default": "Server=127.0.0.1;Port=3306;Database=oms_test;..." },
  "OrderBatch": {
    "RabbitMq": { "Enabled": false }
  },
  "Oms": {
    "TrackService": {
      "Enabled": true,
      "BaseUrl": "http://127.0.0.1:9090",
      "AppKey": "TEST_KEY",
      "AppSecret": "TEST_SECRET",
      "TimeoutSeconds": 5
    },
    "Itfx": {
      "BaseUrl": "http://127.0.0.1:9091",
      "TimeoutSeconds": 5
    }
  },
  "App": { "SendStartupNotification": false }
}
配置节 测试关注点 Mock 策略
Oms:TrackService 创建订单后异步 UpsertSmallBag WireMock 返回 200 + 固定 body
Oms:Itfx 下游预报转发(可选步骤) WireMock 或跳过
OrderBatch:RabbitMq 批量支付/入库等 主链路用同步 API;批量单独用例开启

3.3 数据库初始化顺序

1. db.sql                          # 全量表结构
2. sql/migrate_*.sql               # 增量迁移(issue_template、xhs 等按需)
3. scripts/order_batch_job_tables.sql
4. sql/seed_e2e_order_lifecycle.sql   # 【待建】E2E 专用主数据(见 §4)

4. 主数据 Fixture(测试前置条件)

自动化执行前,库中须存在以下稳定可引用的数据。建议新增 sql/seed_e2e_order_lifecycle.sql,所有 E2E 用例共用同一套编码。

4.1 主数据清单

类别 表 / 模块 测试用固定值 说明
国家 t_country US / CN 收件国用于分区计价
客户 t_customer customerCode=E2E001,Balance >= 10000 支付前须余额充足
RBAC 用户 user 客户主账号,绑定 E2E001 登录拿 JWT
仓库 t_warehouse_address warehouseId=9001 下单、扫描共用
销售产品 t_sales_product productCode=E2E-SP-01 已发布、已绑定规则/价格快照
服务渠道 t_service_channel channelCode=E2E-CH-01 排货后可写入订单
价格 / 分区 t_sales_product_price*、t_kpi_area* 覆盖 US 分区 否则创建订单会 draft + PredeclareFailReason
计重 / 进位 t_weight_rule、t_weight_rounding 匹配 1kg 标准件 入库/outbound 计费依赖
数据权限 数据范围 测试用户可见 E2E 客户 否则列表为空

4.2 登录与请求头

POST /admin/auth/login
Content-Type: application/json

{ "userName": "e2e_customer", "password": "..." }

后续请求:

Authorization: Bearer {accessToken}

客户会话下单时 不传 customerId(由 OmsSessionHelper 解析);内部运营账号测入库/出库时用 运营 RBAC 账号。

4.3 推荐双角色

角色 用途 权限前缀
e2e_customer 下单、支付、查单 Order.PlaceOrder.*、Order.MyOrders.*
e2e_operator 入库、出库扫描 Operation.InboundScan.*、Operation.OutboundScan.*

5. 主流程用例设计(Happy Path)

5.1 流程总览

sequenceDiagram
    participant C as 客户 API
    participant O as OMS OrderService
    participant W as 仓储 Operation
    participant F as Finance
    participant T as Track(Mock)

    C->>O: POST /order/parcel/create
    O-->>C: predeclared + serviceNo
    O->>T: UpsertSmallBag (async)

    C->>W: POST /operation/inbound/create
    W->>O: ApplyReceiveBilling
    W-->>C: pendingPayment + ReceiveTime

    C->>O: POST /order/pay
    O->>F: DebitOrderPay
    O-->>C: pendingShip + PayTime

    C->>W: POST /operation/outbound/create
    W->>O: ApplyShipBilling
    W-->>C: pendingOnline + ShipTime

    Note over C,T: Phase 2 签收
    T-->>O: (待实现) 状态回写
    O-->>C: deliverySuccess + SignTime

5.2 分步用例表

步骤 API 方法 关键入参 期望 OrderStatus 期望副作用
0 可选试算 /order/price-check POST productCode, 件重尺, 收件国 — 返回价格 > 0
1 创建订单 /order/parcel/create POST 见 §5.3 predeclared t_order_fee 预报应收;ServiceNo 生成
2 查详情 /order/detail GET id predeclared 发件人/收件人/申报齐全
3 入库 /operation/inbound/create POST waybillNo, 实重尺 pendingPayment ReceiveTime 非空;入库费 ChargingStage=inbound
4 支付 /order/pay POST { "id": orderId } pendingShip IsPaid=1, PayTime;余额减少;account_flow
5 出库 /operation/outbound/create POST waybillNo, 实重尺 pendingOnline ShipTime 非空;出库费
6 列表 /order/list POST status=pendingOnline — 包含该 serviceNo
7 轨迹 Mock 校验 — — — UpsertSmallBag 被调用 1 次
8 签收 Phase 2 — — deliverySuccess SignTime 非空

5.3 创建订单请求模板(E2E Fixture)

{
  "requestId": "e2e-{uuid}",
  "clientNo": "E2E-CLIENT-{timestamp}",
  "productCode": "E2E-SP-01",
  "cargoAttribute": "general",
  "warehouseId": 9001,
  "length": 30,
  "width": 20,
  "height": 10,
  "actualWeight": 1.2,
  "quantity": 1,
  "receiver": {
    "name": "E2E Receiver",
    "phone": "13800000001",
    "countryCode": "US",
    "state": "CA",
    "city": "Los Angeles",
    "address": "100 Test St",
    "postcode": "90001"
  },
  "sender": {
    "name": "E2E Sender",
    "phone": "13900000001",
    "countryCode": "CN",
    "city": "Shenzhen",
    "address": "Test Warehouse"
  },
  "items": [
    {
      "nameEn": "Test Goods",
      "nameCn": "测试商品",
      "quantity": 1,
      "unitPrice": 10,
      "weight": 1.2,
      "hsCode": "6109100021"
    }
  ]
}

5.4 入库 / 出库请求模板

// POST /operation/inbound/create
{
  "waybillNo": "{serviceNo}",
  "weight": 1.2,
  "length": 30,
  "width": 20,
  "height": 10,
  "warehouseId": 9001
}

// POST /operation/outbound/create
{
  "waybillNo": "{serviceNo}",
  "weight": 1.2,
  "length": 30,
  "width": 20,
  "height": 10,
  "warehouseId": 9001
}

6. 功能模块与 API 映射

业务阶段 后端 Service 前端模块 路由 权限(pageButtonCatalog)
试算 / 下单 OrderService 物流下单 /order/placeOrder Order.PlaceOrder.*
订单管理 OrderService 我的订单 /order/myOrders Order.MyOrders.*
入库 InboundRecordService 入库扫描 /operation/inboundScan Operation.InboundScan.Inbound
出库 OutboundRecordService 出库扫描 /operation/outboundScan Operation.OutboundScan.Outbound
客户余额 CustomerBalanceMutator 客户管理 / 充值 /user/customer User.Customer.*
应收应付 FinanceService 应收应付 /finance/receivablePayable Finance.ReceivablePayable.Query
账户流水 CustomerAccountFlowService — API —
渠道配置 SalesProductService 等 销售产品 / 服务渠道 /channel/* 各模块 Query/Edit
轨迹推送 SmallBagTrackOrderNotifier 我的订单-创建轨迹 — Order.MyOrders.CreateTrackOrder
下游预报 OrderService.DownstreamForward 转发下游 — Order.MyOrders.ForwardDownstreamCreate
批量任务 OrderBatchJobCoordinator 批量任务 /order/batchJobs Order.BatchJobs.*

7. 断言检查点(每层必验)

7.1 HTTP 层

  • 状态码 200(业务错误时 Fake 框架返回统一错误体,需断言 message 为空或 success 标志)
  • 响应 JSON 关键字段类型与枚举值

7.2 订单主表 t_order

SELECT OrderStatus, IsPaid, ReceiveTime, PayTime, ShipTime, SignTime,
       PredeclareFailReason, ChannelCode, ChargeableWeight
FROM t_order WHERE ServiceNo = @serviceNo;
步骤后 OrderStatus IsPaid 时间字段
创建 predeclared 0 全 NULL
入库 pendingPayment 0 ReceiveTime 有值
支付 pendingShip 1 PayTime 有值
出库 pendingOnline 1 ShipTime 有值
签收 deliverySuccess 1 SignTime 有值

7.3 费用 t_order_fee

  • 预报后:存在 Type=receivable 且 ChargingStage 含 forecast/predeclare
  • 入库后:新增 ChargingStage=inbound 行(若产品配置入库计费)
  • 出库后:新增 ChargingStage=outbound 行
  • 支付金额 = 当前应收合计

7.4 客户财务

SELECT Balance FROM t_customer WHERE Id = @customerId;
SELECT * FROM t_customer_account_flow
 WHERE BizType = 'orderPay' AND BizId = @orderId;
  • 支付后:Balance 减少额 = 订单应收合计
  • 流水 Amount 为负,BalanceBefore/After 连贯

7.5 仓储记录

SELECT * FROM t_inbound_record WHERE WaybillNo = @serviceNo;
SELECT * FROM t_outbound_record WHERE WaybillNo = @serviceNo;

7.6 轨迹 Mock

  • WireMock 收到 POST /OrderV2/UpsertSmallBag
  • 请求头含 appKey、timestamp、sign(签名算法见 SmallBagTrackSignHelperTests)

8. 负向与分支用例(摘要)

编号 场景 触发 期望
N01 余额不足支付 客户 Balance < 应收 账户余额不足
N02 未入库支付 跳过步骤 3 直接 pay 当前订单状态不可支付
N03 未支付出库 跳过步骤 4 直接 outbound 订单未付款,禁止出库
N04 重复支付 pay 两次 订单已支付
N05 价格未配置 错误 productCode draft + PredeclareFailReason
N06 黑名单国家/客户 命中黑名单 创建失败,不落库或 draft
N07 拦截单出库 intercept 后 outbound 按业务规则拒绝或警告
B01 问题件流程 mark-problematic problematic + handleStatus=pending
B02 处理完成 handle-status/update handleStatus=processed
B03 批量支付 /order/batch/pay + RabbitMQ Job 全部 success(独立 job)

9. 自动化实现建议

9.1 推荐新建项目结构(后端)

oms0414-back/
  src/
    Oms.E2E.Tests/                          # 新建
      Fixtures/
        OrderLifecycleFixture.cs            # 登录、种子数据、清理
        WireMockTrackServer.cs
      Scenarios/
        OrderLifecycleHappyPathTests.cs
        OrderLifecycleNegativeTests.cs
      sql/
        seed_e2e_order_lifecycle.sql
        assert_order_state.sql
      appsettings.E2E.json

9.2 技术选型

能力 库
API 宿主 复用 SimpleAdminApiTestHost 或 WebApplicationFactory + 真实 MySQL
DB 断言 Dapper / 直接 SqlSugar 查询
HTTP 客户端 HttpClient + System.Text.Json
Mock 外服 WireMock.Net
测试框架 xUnit + FluentAssertions(与现有一致)

9.3 示例测试类骨架(伪代码)

[Collection("OrderLifecycle")]
public class OrderLifecycleHappyPathTests
{
    [Fact]
    public async Task Step01_To_Step05_PendingOnline_ShouldSucceed()
    {
        var token = await Fixture.LoginAsCustomerAsync();
        var create = await Fixture.Api.PostJsonAsync("/admin/order/parcel/create", body, token);
        create.OrderStatus.Should().Be("predeclared");
        var serviceNo = create.ServiceNo;

        await Fixture.Api.PostJsonAsync("/admin/operation/inbound/create", inboundBody, operatorToken);
        await Fixture.AssertOrderStatusAsync(serviceNo, "pendingPayment");

        await Fixture.Api.PostJsonAsync("/admin/order/pay", new { id = create.Id }, token);
        await Fixture.AssertOrderStatusAsync(serviceNo, "pendingShip");
        await Fixture.AssertBalanceDebitedAsync(create.CustomerId, create.Id);

        await Fixture.Api.PostJsonAsync("/admin/operation/outbound/create", outboundBody, operatorToken);
        await Fixture.AssertOrderStatusAsync(serviceNo, "pendingOnline");

        Fixture.TrackMock.VerifyUpsertCalledOnce(serviceNo);
    }
}

9.4 数据隔离策略

策略 做法
A 每用例独立 clientNo E2E-{guid},不删库,靠唯一键隔离(推荐)
B 事务回滚 SqlSugar 难包裹跨 HTTP 请求,不推荐
C 每 job 重建库 CI 慢但最干净;夜间全量 E2E 使用

10. CI/CD 流水线设计

flowchart LR
    PR[PR / Push] --> L1[dotnet test Oms.Tests]
    L1 --> L2[dotnet test IntegrationTests]
    L2 --> E2E{main 分支?}
    E2E -->|是| Docker[启动 MySQL + WireMock]
    Docker --> Seed[执行 seed_e2e_order_lifecycle.sql]
    Seed --> L3[dotnet test Oms.E2E.Tests]
    L3 --> Report[测试报告 / 飞书通知]

10.1 GitHub Actions 示例(片段)

jobs:
  unit-and-integration:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: dotnet test src/Oms.Tests
      - run: dotnet test src/SimpleAdmin.Api.IntegrationTests

  order-lifecycle-e2e:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    services:
      mysql:
        image: mysql:8.0
        env:
          MYSQL_ROOT_PASSWORD: test
          MYSQL_DATABASE: oms_test
    steps:
      - run: mysql -h 127.0.0.1 -uroot -ptest oms_test < db.sql
      - run: mysql -h 127.0.0.1 -uroot -ptest oms_test < sql/seed_e2e_order_lifecycle.sql
      - run: dotnet test src/Oms.E2E.Tests --filter Category=E2E

10.2 本地一键脚本(建议 scripts/run-order-e2e.ps1)

docker compose -f docker-compose.e2e.yml up -d
dotnet test src/Oms.E2E.Tests
docker compose -f docker-compose.e2e.yml down

11. Phase 2:签收段衔接方案

OMS 尚未实现 shipping → deliverySuccess 回写时,任选其一:

方案 说明 适用
P2-A Track 侧完成 调 trackApi/Track/Order/UpdateOrderStatus 置 isCompleted=true 验证轨迹系统闭环
P2-B 测试专用 API 新增 [TestingOnly] POST /order/test/mark-delivered 仅 Testing 环境注册
P2-C SQL 置态 E2E 直接 UPDATE t_order SET OrderStatus='deliverySuccess', SignTime=NOW() 临时;不验 API
P2-D 实现正式回调 Track Webhook → OMS Consumer 生产方案,纳入同一 E2E

推荐路径:先 P2-B unblock E2E,上线前替换为 P2-D 并删除测试 API。


12. 实施路线图

阶段 交付物 工时估
P0 本文档 + seed_e2e_order_lifecycle.sql 1d
P1 Oms.E2E.Tests Happy Path(至 pendingOnline) 2–3d
P1 WireMock Track + 负向用例 N01–N04 1d
P2 签收置态 / Webhook + 完整端到签收 2d
P3 Playwright 冒烟(下单页 + 扫描页) 2d
P3 CI nightly + 测试报告 1d

13. 关键代码与文档索引

后端

路径 说明
Oms.Domain/OrdersAggregate/Consts/OrderStatusCodes.cs 订单状态枚举
Oms.Application/Services/Orders/OrderService.ParcelBilling.cs 创建、入库/出库计费
Oms.Application/Services/Orders/OrderService.cs 支付、列表
Oms.Application/Services/Operations/InboundRecordService.cs 入库
Oms.Application/Services/Operations/OutboundRecordService.cs 出库
Oms.Application/Shared/CustomerBalanceMutator.cs 支付扣款
Oms.Application/Integrations/SmallBagTrack/ 轨迹推送
SimpleAdmin.Api.IntegrationTests/Support/SimpleAdminApiTestHost.cs 集成测试宿主
Oms.Tests/ParcelBillingCalculatorTests.cs 计费单元测试

前端

路径 说明
src/constants/orderStatus.ts 状态常量
src/api/order/index.ts 订单 API
src/api/operation/index.ts 仓储 API
src/views/order/placeOrder/index.vue 下单页
src/views/operation/inboundScan/index.vue 入库
src/views/operation/outboundScan/index.vue 出库

文档

路径 说明
docs/oms系统设计-050801.md 主设计(§4 订单、§6 操作、§10.3 状态码)
docs/物流下单协议.md parcel/create 协议
docs/订单批量处理与异步队列方案0707.md 批量异步

14. 附录:手动冒烟检查清单(5 分钟)

自动化未就绪时,可按此手工验证主链路:

  • 客户登录,余额 ≥ 100
  • 销售产品 E2E-SP-01 已发布且 US 有价格
  • POST /order/parcel/create → 返回 predeclared
  • POST /operation/inbound/create → 订单变 pendingPayment
  • POST /order/pay → pendingShip,余额减少
  • POST /operation/outbound/create → pendingOnline
  • GET /order/detail → ReceiveTime、PayTime、ShipTime 均有值
  • (可选)Track Mock 日志有 UpsertSmallBag

15. 已落地实现(2026-07-08)

交付物 路径
E2E 主数据种子 oms0414-back/sql/seed_e2e_order_lifecycle.sql
E2E 测试项目 oms0414-back/src/Oms.E2E.Tests/
Happy Path 用例 Scenarios/OrderLifecycleHappyPathTests.cs
一键脚本 oms0414-back/scripts/run-order-e2e.ps1

运行方式:

$env:OMS_E2E_ENABLED = "1"
$env:OMS_E2E_CONNECTION = "Server=127.0.0.1;Port=3306;Database=oms;Uid=root;Pwd=你的密码;CharSet=utf8mb4;"
cd oms0414-back
.\scripts\run-order-e2e.ps1

未设置 OMS_E2E_ENABLED 时,E2E 用例自动跳过(不失败)。


维护说明:OMS 实现签收回写后,更新 §1.2 边界表、§5 步骤 8、§11,并将 Phase 2 用例并入 P1 必跑集。