尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

微前端测试要覆盖真实协作链路

微前端测试要覆盖真实协作链路 微前端测试要覆盖真实协作链路独立通过不等于协作正常微前端让子应用可以分别开发和发布但用户运行的是宿主、子应用、共享依赖与接口共同组成的页面。每个仓库的单元测试都通过仍可能在事件载荷、路由前缀、公共样式或卸载清理处发生不兼容。单元测试只能证明孤立代码块在其覆盖范围内符合预期。以user:tenantChange的载荷字段变更为例宿主和子应用仍需通过契约与集成测试确认兼容性。单元环境看不到的协作问题1. 跨应用通信契约EventBus / Store断裂EventBus、Context 或共享 store 都有调用契约。Mock 若由消费方自己编写可能在生产者已经改字段后继续通过。事件 Schema 应由双方共享并分别用真实序列化结果验证未知事件也要有明确处理不能默认视为成功。2. 沙箱隔离泄漏无法在 Mock 环境暴露子应用可能注册全局事件、定时器或向head写入样式。测试环境每次重建 DOM容易掩盖卸载不完整。集成用例应在同一页面依次挂载、卸载和再次挂载检查监听是否重复、样式是否残留、容器是否清空。3. 动态路由与切片加载失效动态 import、远端资源地址和路由 base 只有经过构建与真实加载才能验证。发布候选版本后应在接近部署条件的环境检查入口脚本、分块、静态资源与刷新路由。加载失败时页面要给出可恢复状态不能留下半挂载的宿主。4. 全量 E2E 测试的“慢与不稳定”把所有验证都压进端到端测试也不合适。用例越长、依赖越多失败定位越困难。提交阶段运行契约和少量集成场景候选发布再覆盖真实加载与关键旅程。偶发失败要保存 trace、控制时钟和测试数据不能简单重跑到变绿。按失败位置安排测试不同测试层回答的问题不同顺序也不代表价值高低单元测试Unit Test仅负责子应用内部纯逻辑函数与单一 Component 的状态测试。契约测试Contract Test严格校验子应用间 EventBus 派发事件与全局 Store 的 JSON Schema 映射。沙箱集成测试Sandbox Integration将子应用装载进模拟的基座沙箱中测试 Unmount 后的全局污染与资源卸载状态。一个契约与全局键检查示例下面的MicroAppContractVerifier演示用 Zod 检查一个事件并比较挂载前后的window自有键。它只能发现新增全局键不能检查事件监听器、定时器、DOM、样式和闭包引用globalEventListeners在示例中也未参与检测。实际沙箱测试应针对使用的注册 API 加监控并在真实浏览器中验证卸载。示例对未登记事件直接返回成功接入项目时应根据事件注册表选择拒绝或忽略策略。测试时间戳使用固定值更容易复现示例中的账号和租户也应保持虚构不能替换成生产标识。import { z } from zod; /** * 跨应用 EventBus 通信契约注册表 */ export const TenantChangeEventSchema z.object({ eventId: z.string().uuid(), tenantId: z.string().min(1, 租户 ID 不能为空), userRole: z.enum([admin, member, guest]), timestamp: z.number(), }); export type TenantChangeEvent z.infertypeof TenantChangeEventSchema; /** * 契约校验与沙箱监控引擎 */ export class MicroAppContractVerifier { private globalEventListeners: Setstring new Set(); private initialWindowKeys: Setstring new Set(); /** * 1. 模拟沙箱环境挂载前的快照记录 */ public snapshotSandboxBeforeMount() { this.initialWindowKeys new Set(Object.keys(window)); } /** * 2. 跨应用 EventBus 消息契约断言 (在 CI 契约测试中运行) */ public verifyEventContract(eventName: string, payload: unknown): { success: boolean; errors?: string[] } { if (eventName user:tenantChange) { const result TenantChangeEventSchema.safeParse(payload); if (!result.success) { const errorMsgs result.error.errors.map(e ${e.path.join(.)}: ${e.message}); return { success: false, errors: errorMsgs }; } } return { success: true }; } /** * 3. 沙箱卸载后泄漏检测 (检查子应用是否污染了全局 Window) */ public verifySandboxUnmountLeak(): { leakedKeys: string[] } { const currentWindowKeys Object.keys(window); const leakedKeys: string[] []; currentWindowKeys.forEach(key { // 如果当前 Key 在初始快照中不存在说明发生了全局变量污染 if (!this.initialWindowKeys.has(key) !key.startsWith(__REACT_DEVTOOLS)) { leakedKeys.push(key); } }); return { leakedKeys }; } } // 自动化测试用例示例 (Vitest / Jest 集成) if (require.main module || typeof describe ! undefined) { const verifier new MicroAppContractVerifier(); // 测试用例 1: 校验合法契约 const validPayload { eventId: c9b4a1b0-8e12-4c28-98e3-54f46927d2ab, tenantId: tenant_10086, userRole: admin, timestamp: Date.now(), }; const checkResult verifier.verifyEventContract(user:tenantChange, validPayload); console.log(✅ 契约测试结果:, checkResult.success ? PASSED : FAILED); // 测试用例 2: 捕获非法的字段修改 (如把 tenantId 改成了 tenant_id) const invalidPayload { eventId: c9b4a1b0-8e12-4c28-98e3-54f46927d2ab, tenant_id: tenant_10086, // 错误名称 userRole: admin, timestamp: Date.now(), }; const failCheck verifier.verifyEventContract(user:tenantChange, invalidPayload); if (!failCheck.success) { console.error(❌ 契约测试精准拦截到破损字段:, failCheck.errors); } }各层留下什么证据测试层级验证目标可选工具失败时保留的材料单元测试 (Unit Test)纯函数、组件内部状态Vitest / Testing Library输入、预期和具体断言差异契约测试 (Contract Test)EventBus / Store Payload 与版本兼容Zod Schema / Pact.js事件名、Schema 版本和字段错误沙箱集成 (Sandbox Test)卸载后的监听、DOM 和样式状态浏览器集成测试 受控监控挂载前后快照与残留对象构建加载测试远程入口、分块和资源路径候选制品 测试宿主制品版本、请求与加载错误冒烟 E2E路由、认证与关键协作流程Playwright / Cypresstrace、截图和请求关联标识契约也需要演进规则把 Schema 放进公共包或注册表后还要处理版本兼容。生产者新增可选字段通常与删除字段的风险不同消费方也可能存在发布先后顺序。契约变更应说明兼容窗口并分别使用旧生产者配新消费方、新生产者配旧消费方进行检查。测试数据、日志和 trace 要脱敏远端入口使用受控地址。修复问题后先重跑原协作链路再检查其他订阅方。微前端测试的重点不是某一层覆盖率而是一次变化从生产者经过宿主到消费方时每段契约都有可重放的证据。
返回列表