文档目录
插件测试与调试

简介

本指南面向 DouPHP 框架的插件开发者,聚焦“插件单元测试、集成测试、第三方服务模拟、调试工具、日志最佳实践、常见错误排查、性能与安全测试”等主题。文档以现有支付插件(支付宝、微信支付)和登录插件(Google、微信登录)为示例,结合框架提供的 Provider/Service/DTO/Registry 体系,给出可操作的测试策略与排障方法。

项目结构

DouPHP 插件系统采用“契约 + 提供者 + 服务 + DTO + 注册表”的分层设计:

  • 契约层:定义统一的 Provider 接口(支付、连接、可轮询、可对账)。
  • 提供者层:具体插件实现(如 AlipayProvider、WxpayProvider),负责编排 Service 调用。
  • 服务层:封装第三方 SDK 与业务逻辑(如 AlipayService、WxpayService)。
  • DTO 层:标准化请求/响应数据载体(PaymentRequest、PaymentCallbackPayload、PaymentQueryRequest、PaymentQueryResult)。
  • 注册表:自动发现并加载 manifest.php 声明的 Provider,注入容器。
graph TB
subgraph "契约"
I1["PaymentPluginProviderInterface"]
I2["ReconcilablePaymentProviderInterface"]
I3["PollablePaymentProviderInterface"]
end
subgraph "提供者"
P1["AlipayProvider"]
P2["WxpayProvider"]
end
subgraph "服务"
S1["AlipayService"]
S2["WxpayService"]
end
subgraph "DTO"
D1["PaymentRequest"]
D2["PaymentCallbackPayload"]
D3["PaymentQueryRequest"]
D4["PaymentQueryResult"]
end
subgraph "注册与配置"
R1["PaymentPluginRegistry"]
R2["ConnectPluginRegistry"]
V1["ManifestValidator"]
C1["PluginServiceProvider"]
CFG["Config"]
end
I1 --> P1
I1 --> P2
I2 --> P1
I2 --> P2
I3 --> P2
P1 --> S1
P2 --> S2
P1 --> D1
P1 --> D2
P1 --> D3
P1 --> D4
P2 --> D1
P2 --> D2
P2 --> D3
P2 --> D4
R1 --> P1
R1 --> P2
R2 --> P1
R2 --> P2
V1 --> R1
V1 --> R2
C1 --> R1
C1 --> R2
CFG --> S1
CFG --> S2

核心组件

  • 支付契约与扩展
    • PaymentPluginProviderInterface:统一 start/notify/finish 能力。
    • ReconcilablePaymentProviderInterface:增加 query 主动对账能力。
    • PollablePaymentProviderInterface:支持 Native 扫码轮询查询。
  • 插件提供者与服务
    • AlipayProvider/WxpayProvider:薄包装,委托到 Service。
    • AlipayService/WxpayService:对接第三方 SDK,处理验签、状态机推进、回调与查询。
  • DTO
    • PaymentRequest:发起支付的入参(订单号、金额等)。
    • PaymentCallbackPayload:异步/同步回调载荷。
    • PaymentQueryRequest/PaymentQueryResult:对账查询的请求与结果模型。
  • 注册与校验
    • PaymentPluginRegistry/ConnectPluginRegistry:扫描 manifest.php 并实例化 Provider。
    • ManifestValidator:白名单校验 manifest 键与 provider 命名空间。
    • PluginServiceProvider:按需绑定真实或空实现,保证调用面稳定。

架构总览

下图展示一次“发起支付 → 异步通知 → 同步回跳 → 主动对账”的完整流程,覆盖支付宝与微信两种典型路径。

sequenceDiagram
participant Client as "客户端"
participant Reg as "PaymentPluginRegistry"
participant Prov as "Provider(Alipay/Wxpay)"
participant Svc as "Service(Alipay/Wxpay)"
participant SDK as "第三方SDK"
participant PS as "PaymentService"
Client->>Reg : 获取指定插件Provider
Reg-->>Client : Provider实例
Client->>Prov : start(PaymentRequest)
Prov->>Svc : start(request)
Svc->>SDK : 创建订单/生成支付参数
SDK-->>Svc : 支付链接/二维码/JS参数
Svc-->>Prov : HTML/URL
Prov-->>Client : 返回前端渲染内容
Note over Client,SDK : 用户完成支付后,第三方回调
SDK-->>Prov : notify(payload)
Prov->>Svc : notify(payload)
Svc->>PS : markSucceeded(paymentSn, transactionId, raw)
PS-->>Svc : 成功
Svc-->>Prov : success/fail
Client->>Prov : finish(payload)
Prov->>Svc : finish(payload)
Svc-->>Prov : 跳转URL
Prov-->>Client : 重定向到订单页
Note over Client,SDK : 定时轮询或对账任务
Client->>Prov : query(status/status_url)
Prov->>Svc : query(PaymentQueryRequest)
Svc->>SDK : 查询交易状态
SDK-->>Svc : 状态
Svc-->>Prov : PaymentQueryResult
Prov-->>Client : pending/success/closed/notFound

详细组件分析

支付宝插件(AlipayProvider/AlipayService)

  • 职责边界
    • Provider:暴露 pluginId/meta/start/notify/finish/query,委托 Service。
    • Service:组装 SDK 请求、验签、调用 PaymentService 推进状态、构建对账查询。
  • 关键行为
    • start:构造页面支付请求,返回 HTML。
    • notify:验签通过后标记支付成功。
    • finish:验签成功后发送邮件并跳转订单页。
    • query:根据 paymentSn 查询交易状态,映射为 succeeded/pending/closed/notFound。
classDiagram
class AlipayProvider {
+pluginId() string
+meta() array
+start(request) string
+notify(payload) string
+finish(payload) string
+query(request) PaymentQueryResult
}
class AlipayService {
+start(request) string
+notify(payload) string
+finish(payload) string
+query(request) PaymentQueryResult
-buildConfig() array
-encodeRaw(data) string
-responseToArray(response) array|null
}
AlipayProvider --> AlipayService : "委托"

微信支付插件(WxpayProvider/WxpayService)

  • 职责边界
    • Provider:同时实现可轮询与可对账能力,委托 Service。
    • Service:按 UA 选择 JSAPI/H5/Native;统一 notify;status 轮询;query 对账。
  • 关键行为
    • start:根据环境选择支付方式,返回按钮/二维码/跳转链接。
    • notify:使用 SDK 验签并通过 PaymentService 推进状态。
    • status:Native 扫码轮询,命中 SUCCESS 即推进状态。
    • query:OrderQuery 查询,映射为 succeeded/pending/closed/notFound。
flowchart TD
Start(["进入 WxpayService.start"]) --> UA{"是否微信内置浏览器?"}
UA --> |是| JSAPI["startJsapi"]
UA --> |否| Mobile{"是否移动端?"}
Mobile --> |是| H5["startH5"]
Mobile --> |否| Native["startNative"]
JSAPI --> ReturnA["返回JS支付参数"]
H5 --> ReturnB["返回MWEB跳转"]
Native --> ReturnC["返回二维码+轮询脚本"]

登录插件(Google/Wxlogin)

  • Google 登录 Provider 基于 OAuth2/OIDC,start 跳转授权页,finish 用 code 换 token 并拉取用户信息。
  • 与支付 Provider 类似,通过 ConnectPluginRegistry 自动发现与实例化。

依赖关系分析

  • 契约与实现解耦:Provider 仅依赖接口,便于替换与 Mock。
  • 注册表集中管理:manifest.php 声明 provider FQCN,由 Registry 扫描并实例化。
  • 配置注入:Service 通过 Config 读取插件配置,避免硬编码。
  • 外部依赖:各 Service 内 require_once SDK 文件,隔离第三方库。
graph LR
M["manifest.php"] --> V["ManifestValidator"]
V --> R["PaymentPluginRegistry / ConnectPluginRegistry"]
R --> P["Provider(Alipay/Wxpay/Google)"]
P --> S["Service(Alipay/Wxpay)"]
S --> CFG["Config"]
S --> SDK["第三方SDK"]

性能考虑

  • 延迟加载 SDK:Service 仅在需要时 require_once SDK 文件,减少启动开销。
  • 轮询节流:Native 扫码轮询有最大次数限制,避免频繁请求。
  • 对账幂等:notify/finish/query 均通过 PaymentService 推进状态,天然具备幂等性。
  • 日志分级:SDK 日志可按级别输出,生产建议关闭低级别日志以减少 I/O。

故障排查指南

  • 常见问题定位
    • 配置缺失:Service 在 start 前检查必要配置项,缺失会抛出异常或返回失败。
    • 验签失败:notify 中 SDK 验签失败直接返回 fail,需核对密钥与回调参数。
    • 对账异常:query 返回 failed/notFound/pending,需查看第三方返回码与消息。
  • 日志与调试
    • 微信支付 SDK 日志:写入 storage/log/payment/wxpay/ 日期日志文件,便于回溯。
    • SMTP 调试:可通过设置 Debugoutput 与 do_debug 级别观察 SMTP 握手过程。
    • 最小化复现:参考 devtools 下的 smoke 脚本模式,独立引导框架并执行断言。
  • 安全与权限
    • manifest 校验:仅允许 plugin_group/provider 键,provider 必须位于 Dou\Plugin\ 命名空间。
    • 回调安全:所有回调均需验签后再执行业务逻辑。

结论

DouPHP 插件系统通过清晰的契约与分层,使插件的单元测试与集成测试具备良好的切入点:以 Provider 为边界进行 Mock,以 Service 为核心验证业务逻辑,以 DTO 作为输入输出断言点。配合注册表的自动发现与 manifest 的安全校验,可在保证安全的前提下快速迭代与回归。对于第三方服务,优先通过本地日志与最小化 smoke 脚本进行问题定位与回归验证。

附录

单元测试编写要点

  • 目标
    • 验证 Provider 正确委托 Service。
    • 验证 Service 对 SDK 的调用参数与返回值映射。
    • 验证 DTO 的序列化/反序列化与边界值。
  • 方法
    • 使用接口与 DTO 进行隔离:对 PaymentPluginProviderInterface 进行 Mock,断言传入的 PaymentRequest/PaymentCallbackPayload。
    • 针对 Service:Mock 第三方 SDK 类或拦截其网络调用,断言最终状态推进。
    • 针对 Registry:构造不同 manifest.php 内容,校验白名单与命名空间限制。
  • 参考路径
    • PaymentPluginProviderInterface.php:24-66
    • ReconcilablePaymentProviderInterface.php:24-49
    • PaymentRequest.php
    • PaymentCallbackPayload.php
    • PaymentQueryRequest.php
    • PaymentQueryResult.php

集成测试策略

  • 场景
    • 支付全流程:start → 回调 → finish → query。
    • 轮询流程:Native 扫码 → 多次 status 查询 → 成功跳转。
    • 登录流程:start → finish 获取用户信息。
  • 方法
    • 使用 smoke 脚本模式引导框架,构造真实路由与请求上下文。
    • 使用内存/临时存储替代数据库与文件系统,确保可重复执行。
    • 对第三方网络调用使用本地 mock 或代理。
  • 参考路径
    • ai-prompt-composer-smoke.php:15-70
    • WxpayService.php:98-134
    • AlipayService.php:122-172

模拟第三方服务的技巧

  • 支付网关
    • 使用本地 mock 返回固定报文,覆盖成功、失败、未找到、关闭等分支。
    • 对验签逻辑,提供合法/非法签名用例,验证 reject 路径。
  • 登录平台
    • 模拟 OAuth 回调,构造不同 user info 与错误码,验证登录失败处理。
  • 邮件服务
    • 使用 SMTP 调试输出,捕获握手与命令交互,定位连接与认证问题。

调试工具与日志最佳实践

  • 日志
    • 微信支付 SDK:按天落盘,生产环境降低日志级别。
    • SMTP:开启 DEBUG_CONNECTION/DEBUG_SERVER 辅助定位连接问题。
    • 配置:通过 Config 统一管理开关与通道,避免硬编码。
  • 工具
    • Smoke 脚本:最小化引导框架,快速复现场景。
    • 路由与中间件:利用框架路由与中间件记录请求链路。
  • 参考路径
    • WxpayService.php:447-455
    • Smtp.php:102-127
    • Config.php:23-64
    • ai-prompt-composer-smoke.php:15-70

常见错误排查清单

  • 配置不完整:检查 app_id、密钥、证书路径等。
  • 验签失败:核对回调参数顺序、编码、密钥版本。
  • 轮询超时:检查 status 接口频率与最大次数。
  • 对账不一致:对比 query 返回码与业务状态机。
  • 邮件发送失败:检查 SMTP 主机、端口、认证与 TLS。

性能测试与安全测试

  • 性能测试
    • 对 query/status 接口进行压测,关注第三方限流与重试策略。
    • 评估日志 I/O 对吞吐的影响,合理设置日志级别与采样率。
  • 安全测试
    • 校验 manifest 白名单与命名空间限制,防止恶意 Provider 注入。
    • 对所有回调进行验签与参数白名单校验,防止篡改。
    • 敏感配置(密钥、证书)不落盘或加密存储。
添加日期:2026-10-05