跳转到内容

如何验收独立的前端 Release?

单独的绿色 Pipeline 并不能证明整个产品可用

Section titled “单独的绿色 Pipeline 并不能证明整个产品可用”
Shell Pipeline ✅
Remote A Pipeline ✅
Remote B Pipeline ✅
Remote C Pipeline ✅
完整产品 ❌

这个状态乍看很矛盾:每一条 Pipeline 都是绿色的,组合之后的产品却不可用。也许某个 Remote 根本加载不出来;也许 Shell 提供的 Authentication Context 与 Remote 预期不同;也许 Mounting 正常,但 Unmounting 后留下了 Global State;也许 Artifact Build 没问题,但发布后的真实地址根本访问不到。

绿色的单体 Pipeline 并不是没有价值。

它们只是各自证明了一个有限范围内的事实。

Shell 验证了自己的责任。Remote 也验证了自己的责任。还没有被证明的是:这些部件在当前真正要交付的组合里是否能够一起工作。

一个很自然的反应,是把每一次修改重新拉回完整系统验收:所有 Remote Release 都必须进入中央环境,跑一条很长的 End-to-End Pipeline,再等待统一审批。技术上 Artifact 仍然是独立的;组织和运行上,架构却重新耦合在了一起。

因此真正的问题不是“到底应该本地测试,还是 Integration Test”。

而是:

哪一层责任,应该在哪一块验收面上被证明?

一个可以独立发布的 Remote,需要自己的、足够真实的验收面。这个环境要做到多完整,取决于 Release 的责任范围与风险。根据 Test Goal,可以使用 Stub、真实 Backend、Ephemeral System,或者一个可以独立启动的业务 Slice。随后,再用一个有针对性的 Smoke Test,把该 Release Candidate 与计划使用的 Shell Version 进行 Composition 验证。

独立 Release 需要独立验收,但不能把“我自己测过了”误当成“整个组合一定没问题”。

Shell 与多个 Remote 的 Pipeline 都成功,但最终组合仍然失败;在本地验证与完整产品之间,需要一条专门验证 Composition 的边界。

一个 Remote 并不会因为自己的 Pipeline 能生成独立 Artifact 就自动变得独立。Artifact 的确可以单独 Version、Build 和 Publish。但只有负责团队也能独立评估这个 Release Candidate,这种独立性才真正有价值。

团队需要能够启动它、用足够真实的方式操作它、自动化测试它,也能够做业务或视觉验收。团队还需要提供或接入定义清楚的 Dependency。最重要的是:这种评估不能原则上依赖完整产品全部启动。

这里的“验收”不只是人工点一下“批准”。指的是对这个具体 Release Candidate 的可追踪评估——可能通过自动化测试、业务检查、视觉验证,或者几种方式组合完成。

一个独立 Artifact 如果没有自己的验收面,只是可以独立发布,却不能独立验证。

这并不意味着 Remote 必须完全隔离运行。独立验收环境完全可以连接真实 Backend、Identity Provider 或其他 Shared Service。关键是团队能否为自己的 Release 独立准备、或者稳定使用这些依赖,而不必等待中央产品级审批。

这样的环境可以比完整产品小很多。但它必须足够真实地覆盖 Release 的责任范围。如果为了简单而省略掉恰好最相关的风险,那就不是真正可靠的独立验收。反过来,如果只是为了验证一个局部 Remote 风险,却每次都启动完整产品,也不意味着测试质量更高。

对于独立发布的 Remote,单纯用 Unit Test、Integration Test 和 E2E Test 三层分类并不够。更有价值的是看:这个 Test 要覆盖的风险到底有多远。

本地实现风险
└── Unit Test 与 Component Test
Remote 内业务风险
└── 在 Remote 自己的环境中验收
Contract 风险
└── Contract Test 与经过验证的 Stub
Composition 风险
└── 当前 Shell 中的定向 Smoke Test
产品级流程
└── 少量系统级 End-to-End Test

一个本地 Validator 不需要完整产品 Shell。业务范围只存在于某个产品区域的 Flow,也不应该等到中央总体环境才第一次被验证。Platform Contract 发生变化,也不能靠再写几个 Component Test 解决。同样,一个 Remote 自己测试完全正确,仍然可能在真实 Composition 中失败。

Test 的大小应该与风险传播范围匹配。

这样形成的不是一张死板 Test Pyramid,而是一份责任分布图。风险越跨出自己的边界,验证越需要接近真实 Integration Boundary;风险越局部,验收就越不应该依赖无关系统部分。

Mini Host:最小但足够真实的验收面

Section titled “Mini Host:最小但足够真实的验收面”

对于很多 Remote,Mini Host 是最小可用的验收环境。它不是把 Remote 当作一堆孤立 Component 启动,而是在一个受控 Platform Context 中运行。

Mini Host 中的 Remote
├── 自己的 Entry Point
├── Routing
├── Theme 与 Locale
├── 定义好的 AuthContext
├── Platform Adapter
└── API Stub 或真实 API

Mini Host 不是 Productshell 的复制品。它可以提供 Remote 真正依赖的技术前提:Routing、Theme、Locale、定义清楚的 Authentication Context、Platform Adapter、受控 API Access。但它不应该复制真实 Shell 的全产品 Navigation、Layout、Global State 或业务逻辑。如果这么做,只会产生第二个 Shell,并且以后必须持续与第一个 Shell 同步。验收环境本身就会成为新的耦合源。

它的职责更小:提供 Remote 运行所需要的 Contract 与技术前提。

在这里,可以测试产品区域内部 Navigation、Loading/Empty/Error State、不同 UI Capability 和 Responsive Behavior。也可以验证业务 Use Case、依赖不可用时的行为、Mounting 与 Cleanup,以及真实 Release Candidate 的可操作性。

Mini Host 模拟的是 Platform Boundary,不是整个产品。

这并不是把业务逻辑从真实平台中“隔离出去”,而是在一个显式 Platform Contract 上验证它。也正因为范围被控制,Mini Host 才有价值:它足够真实,又不会让每一次 Remote 验收都等待完整产品。

如果 Remote 的验收原则上离不开完整 Shell,它就不是真正可以独立测试的。

当然,Mini Host 也有边界。它能证明 Remote 可以在约定的 Platform Contract 下工作,却不能证明当前 Production Shell 正好也以完全相同的方式满足这个 Contract。后一个问题属于 Composition Test。

Stub 必须建立在可验证 Contract 上

Section titled “Stub 必须建立在可验证 Contract 上”

Stub 对独立验收环境非常有吸引力。它可以提供可复现数据、明确 Error State 和特定 Permission Scenario;启动快,不会争夺共享测试系统,也很适合 Pull Request Preview。现实环境中很难稳定制造的 Edge Case,也可以通过 Stub 精确复现。

但这种控制感也可能是假的。

真实 Provider 已经改了 Contract,Stub 却还可以让所有 Test 继续通过。真实 API 新增 Required Field、改变 Status Code,或者 Lifecycle 顺序变化,本地模拟完全可能毫无感觉。

所以 Stub 不应该只是“Remote 当前最方便使用的假实现”。它应该由经过验证的 Contract 生成,或者至少和真实 Provider 一起被同一个 Contract Test 约束。

对于 Platform Contract,这可能包括 AuthContext、Theme、Locale、Navigation、Notifications、Mounting 以及 Lifecycle Interface。对于 API Contract,则包括 Request/Response Structure、Status Code、Error Model、Required Field 与业务上重要的 Variant。

Remote
└── 依赖某个 Contract
Stub
└── 实现同一个 Contract
Platform 或 API
└── 证明自己仍满足该 Contract

Contract Test 就这样把独立验收和真实 Integration 连接起来。真正重要的问题不是“这个 Stub 看起来像不像”,而是 Consumer 和 Provider 是否仍然遵守同一份约定。

只有当 Stub 映射的是与真实 Platform/API 相同、且被验证过的 Contract,它才值得信任。

Contract Test 也不会替代业务验收。它不会告诉你某个 Use Case 是否容易理解、是否完整、业务结果是否正确。它保护的是业务验收赖以成立的那条边界。

独立 Remote 验收并不等于所有 Dependency 都必须模拟。

Remote 可以在 Mini Host 或自己的 Entry Point 中启动,同时连接现有 Development 或 Test Environment:

Remote
├── Mini Host 或自己的 Entry Point
└── 现有 Development/Test Environment

这种模式可以验证真实 HTTP Contract、真实 Authentication、实际数据格式和真实 Error Response。跨 Backend 的业务 Flow、与已有数据和 Service 的 Integration 也会被覆盖。

优势是现实程度更高,同时 Infrastructure Cost 仍然可控。团队不需要为每个 Release 都创建完整环境,但仍然和真实系统交互。

代价是会产生另外一种依赖。共享 Test Environment 可能不稳定或临时不可用;Test Data 会变化;多个团队互相影响;特定初始状态很难重复构造。Test 失败时,原因可能是 Release Candidate,也可能只是环境被其他东西改坏了。

因此 Stub 和真实系统不是“低质量 vs. 高质量”的等级关系。

它们回答不同的问题。

Stub 更适合可控制状态和可复现 Edge Case;真实 Backend 更能证明实际运行中的通信是否仍然成立。

独立验收并不意味着模拟所有 Dependency。它意味着团队可以独立使用完成验收所需的环境。

为 Pull Request 创建 Ephemeral Environment

Section titled “为 Pull Request 创建 Ephemeral Environment”

如果本地 Stub 和共享 Backend 都无法同时满足现实程度和可复现性,可以考虑 Ephemeral Environment。它为一个 Branch 或 Pull Request 临时创建,在工作结束后删除。

Pull Request
Build Release Candidate
创建临时环境
├── Remote
├── 所需 API
├── Database
└── 必要 Infrastructure
自动 E2E Test 与验收
删除环境

这种环境可以把真实 System Component 与可复现的起始状态结合起来。它避免团队争夺同一套 Test Environment,也让 Pull Request 真正产生的 Release Candidate 直接可访问。自动化 Test 与人工验收因此作用在同一个版本上。

Release Candidate 不再只是 Pipeline 里的抽象 Artifact。Preview Link 可以让业务验收、视觉检查、Accessibility Test、Responsive Test、不同 Test Identity,以及特定 Error/Empty/E2E Scenario 直接操作真实 Candidate。

但 Preview 仍然不能证明真实 Composition 一定工作。它验证的是 Remote 在这套临时环境里的行为。当前 Production Shell 仍然是一条独立 Integration Boundary。

Ephemeral Environment 也有明显成本。Provisioning 和 Startup 更慢,Infrastructure Cost 更高;Test Data 和依赖 Service 需要自动准备。当系统要求这些环境可重复创建、可观察、并可靠清理时,Operations Complexity 会显著增加。

Branch Workflow 到底像 GitHub Flow,还是采用其他模式,并不会改变这个架构原则。环境由 GitHub Actions、GitLab、Azure DevOps 还是别的系统创建,也不是关键。真正的问题是:额外现实程度,是否值得为当前 Release 风险支付这些成本。

在纵向切分的 Self-contained Systems 架构中,独立验收面可以比单个 Remote 更大:

业务 SCS
├── Remote 或独立 Frontend
├── 自己的 APIs
├── 自己的 Database
├── Authentication Integration
├── Storage
└── 其他业务必需 Infrastructure

这样,完整业务 Slice 可以独立启动并验证。根据 Domain,可能包括 Keycloak 之类 Identity Provider、Database、MinIO 之类 Object Storage、Message Broker 或其他业务 API。

这种独立验收能力并不是由微前端单独带来的,而是整个系统更进一步纵向切分的结果。团队拥有的不只是一个独立 Frontend Artifact,而是一块可以独立运行的业务系统。

完整 SCS 是一种可能的验收面。

不是每个 Remote 的最低要求。

对很多产品区域来说,这种环境太昂贵,甚至组织上根本无法提供。只有当职责、数据和 Operations 本来就纵向切开时,它才真正合理。

这些不同验收面不是一条“成熟度阶梯”。

Remote + Stubs
└── 可控 UI 与 State 验证
Remote + 现有 Backend
└── Frontend 对真实 API
Remote + Ephemeral Vertical Environment
└── 可复现地验证 Release Candidate Integration
完整可启动 SCS
└── 验收完整业务 Slice
Release Candidate + 当前 Shell
└── 验证 Composition

最大、最贵的环境并不自动是最好的。为了一个很小的视觉 Bug 启动完整业务 SCS 可能完全过度;对 Authentication Flow 的关键修改只使用一个随手写的 Stub 又可能远远不够。共享 Backend 对简单 Read Use Case 也许很好,但并不适合复现复杂 Failure Case。

选择取决于责任范围、风险传播范围和修改关键性。Provisioning Time、Infrastructure Cost、所需现实程度和可复现性同样重要。

验收环境不应该尽可能大,而应该足够真实地覆盖 Release 的责任与风险。

“尽可能小地测试”不等于“人为隔离地测试”。

五种并列验收与集成面:Remote+Stub、现有 Backend、Ephemeral Environment、完整业务 SCS,以及当前 Productshell 中的 Composition Smoke Test。

Remote 或 SCS 自己的环境,是深入业务验收的地方。产品区域的 Use Case、UI Behavior、Validation、本地 Navigation、Error/Empty State 和 Permission Projection 都应该在这里测试。与团队负责 API 的交互,以及 Boundary 内部的业务 End-to-End Scenario,也属于这里。

这些 Test 完全可以很深入。可以覆盖不同数据状态、Identity 和 Failure Situation,也可以跨多步内部 Navigation。负责团队同时拥有 Domain Knowledge 和直接判断故障原因的能力。

业务验收应该发生在业务责任所在的地方。

因此,Shell 不应该为每个 Form Rule、每种内部 State Variant、每个局部 Use Case 都重新成为完整 Test Environment。否则 Composition Layer 会逐渐重新变成所有产品区域的中央验收平台。

完成独立验收后,仍然需要一个有针对性的 Integration Test,把 Release Candidate 与当前 Production Shell,或者本次 Release 计划使用的 Shell Version 组合起来:

目标 Shell
+
Remote Release Candidate
└── Composition Smoke Test

这个 Test 不再重复完整业务逻辑。它验证的是:真正可以发布的 Artifact 是否能在真实 Composition 中工作。包括是否可访问、是否能加载与激活、Mount/Unmount 是否正确。真实 Route 必须能访问;AuthContext、Theme、Locale 以及其他 Platform Contract 必须正确到达 Remote。

至少一个关键入口应当能够工作。进入和离开 Remote 的 Navigation 不能损坏。Remote 不应污染其他 Shell 区域。一个定义清楚的 Failure State,也应该能够按真实 Platform 预期展示。

业务在自己的验收面中验证。Composition 在真实 Shell 中验证。

Composition Test 应该有意识地保持窄。它证明两个已经分别验证过的责任区域,在当前组合中仍然兼容。它不是第二轮完整业务验收,也不替代 Remote 自己更深入的 Test。

左侧是自己的环境中的深入业务验收,右侧是在真实 Productshell 中保持窄范围的 Composition Test。

产品级 E2E Test 应该对应产品级风险

Section titled “产品级 E2E Test 应该对应产品级风险”

如果某个 Use Case 本来就跨多个产品区域,完整 End-to-End Test 仍然合理。

Login
→ Navigation 到 Remote A
→ 执行业务修改
→ Backend State 更新
→ 切换到 Remote B
→ 产品级 Projection 可见

这个 Flow 的风险确实是产品级的。它不只取决于某一个 Remote 内部业务,也不只取决于 Platform Contract,而是一个业务结果跨多个 Responsibility Boundary 后必须在产品里保持一致。此时系统级 Test 正合适。

不合理的是:每个本地 Form Validation、Remote 内部细节,都必须经过完整 Shell、所有 Remote、所有 Backend 和统一系统环境验证。这样的 Test 慢、贵、难诊断,而且会把本地责任重新搬到中央 Pipeline。

产品级 Test 用来验证产品级风险,不应该替代每个 Remote 的本地 Test Strategy。

环境越大,里面运行的 Scenario 就应该越精选。少量真正跨产品的 Flow,通常比大量“只是碰巧通过完整产品点击”的局部细节测试更可靠。

Affected Strategy 用来选择相关验证

Section titled “Affected Strategy 用来选择相关验证”

不是每次修改都影响所有 Remote,也不是每次修改都需要经过所有 Test Level。Affected Strategy 可以根据变化与已建模依赖关系缩小验证范围。

Pull Request 中的修改
Affected Analysis
├── Build 受影响 Remote
├── 运行相关 Test
├── 创建必要 Preview
└── 验证受影响 Composition

Nx 这类 Monorepo Tool 可以通过 Project Graph 和修改过的 Input 推导可能受到影响的 Project 或 Target。由此选择 Build、Unit/Component Test、Contract Test、E2E、Preview Deployment 或 Composition Smoke Test。

Affected 本身不是一种 Test,也不是质量保证。

它只决定:基于这次修改,哪些验证看起来相关。

它并不决定这些验证应该有多深入。

Affected 决定“这次变化应该检查什么”,不决定“这个检查必须有多深”。

选择质量依赖 Project/Dependency Graph 是否正确。隐藏 Runtime Coupling、动态 Configuration 或 External Contract 都可能被静态分析漏掉。因此,一条绿色 Affected Pipeline 也不能自动证明真实 Composition。它只是有针对性地减少工作量,并不能替代明确 Integration Strategy。

Version 组合应该有针对性测试,而不是全部穷举

Section titled “Version 组合应该有针对性测试,而不是全部穷举”

独立 Release 会产生多种潜在 Version 组合。

完整 Matrix 很快就不可管理:

多个 Shell Version
× 多个 Remote Version
× 其他 Remote
× 多个 Browser
= 几乎无法控制的 Test Matrix

因此架构必须定义:哪些组合是真正支持的。

通常值得测试的是当前 Production Shell 与新 Remote Candidate,以及新 Shell 与当前 Production Remote。在 Migration 期间,还可能需要同时测试旧/新 Contract Version 或真正并行运行的 Variant。

并不是每个技术上可能的 Version 组合,都是产品承诺支持的配置。

应该测试承诺的 Support Range,而不是历史上所有可能组合。限制范围不是放弃质量,而是让真正重要的组合能够被可靠验证。

对已经发布的 Artifact 做 Smoke Test

Section titled “对已经发布的 Artifact 做 Smoke Test”

Deployment 前的所有验证针对的都是 Release Candidate。它们不能证明最终真正发布到目标地址的就是这份 Artifact,也不能证明 Production Shell 真正能加载它。

所以发布之后,应该有一个小型 Smoke Test:

已发布 Artifact
├── 可访问
├── 可激活
├── 核心 Route 工作
├── 关键入口工作
└── Error Rate 没有立即异常上升

这个 Test 可以同时有技术和少量业务内容。例如确认 Remote Artifact 可访问、Manifest 或 Entry Point 正确、Mounting 成功、Authentication Context 被识别。还可以通过一个小而安全、可重复的 Read Use Case 作为业务入口,同时观察 Telemetry 是否出现即时 Error Spike。

它不重复完整验收。

它回答另一个问题:

Release 前,我们验证 Candidate。Release 后,我们确认真正进入产品的正是这份 Artifact,并且它能工作。

最终仍然可能出现这样的状态:

Remote Tests ✅
Contract Tests ✅
Preview Acceptance ✅
Shell Tests ✅
Composition ?

答案不是重新建立一条“每次都跑完整世界”的中央 Pipeline。

答案是分层、分责任的 Test Strategy:可以独立发布的 Remote,需要一块团队可以自己准备和控制的验收面。它可以使用 Stub、真实 Backend、Ephemeral Infrastructure,或者一个能够独立启动的业务 SCS。关键不是环境最大,而是是否真实覆盖 Release 的责任与风险。

绿色的单独 Pipeline 本身没有问题。

真正的问题是:架构里没有任何地方验证 Composition。

Integration 必须测试,但不能因此把所有业务验收重新塞回中央 Test Pipeline。

如果一个 Release 的验收仍然必须依赖完整产品,它就不是真正独立的 Release。