如何用jasmine-marbles快速测试NgRx Effects?angular-contacts-app-example单元测试完整指南
如何用jasmine-marbles快速测试NgRx Effectsangular-contacts-app-example单元测试完整指南【免费下载链接】angular-contacts-app-exampleFull Stack Angular PWA example app with NgRx NestJS项目地址: https://gitcode.com/gh_mirrors/an/angular-contacts-app-exampleangular-contacts-app-example是一个基于 Angular NgRx NestJS 的全栈 PWA 通讯录应用使用ngrx/effects管理 HTTP 请求和 WebSocket 等副作用。本文以该项目为蓝本手把手教你如何用jasmine-marbles库对 NgRx Effects 编写高效、可读性强的单元测试。为什么选择 jasmine-marblesNgRx Effects 本质上是一组响应式数据流接收 Action经过异步操作HTTP、Socket再发射新的 Action。传统测试需要手动管理subscribe、take和异步时序非常繁琐。jasmine-marbles用直观的「marble 时间线」把异步流变成几行字符串让你一眼看清什么时刻发什么符号含义-1帧时间流逝a/b发射对应事件\|流完成#流报错只需引入jasmine-marbles项目已声明jasmine-marbles: ^0.5.0即可获得hot()、cold()和toBeObservable()三个核心 API。项目中的 NgRx 数据流架构在动手写测试前先理解 contacts-effects.ts 中的 5 条 EffectloadAll$ → contactsService.index() → loadAllSuccess load$ → contactsService.show() → loadSuccess create$ → contactsService.create() → createSuccess update$ → contactsService.update() → updateSuccess destroy$ → contactsService.destroy()→ removeSuccess每条 Effect 的结构一致ofType(触发Action) → 调用 Service → 映射为成功Action。所有 Action 定义集中在 contacts-actions.ts而状态变更逻辑由 contacts-reducer.ts 中的ngrx/entityAdapter 处理。测试环境搭建Mock 替代真实 ServiceEffects 依赖ContactsService发起 HTTP和ContactsSocketServiceWebSocket。测试时绝不能打真实请求项目提供了 contacts-mock.service.tsindex()返回预设的 2 条联系人show()返回 id1 的 johncreate()返回 id4 的新联系人update()/destroy()同样返回固定数据在测试文件中通过 Angular 依赖注入用useClass: ContactsServiceMock替换真实 Service这是整个测试能离线跑通的关键。核心 API 速查hot 与 cold打开 contacts-effects.spec.ts每个用例都遵循固定三步// 1️⃣ 定义输入第2帧发射 loadAll Action actions$ hot(--a-, { a: actionDispatched }); // 2️⃣ 定义期望输出第2帧发射 loadAllSuccess const expected cold(--b, { b: actionExpected }); // 3️⃣ 断言Effect 输出流与期望完全匹配 expect(effects.loadAll$).toBeObservable(expected);hot()— 模拟外部驱动的输入流多个订阅者共享同一时间线适合模拟 Store 中其他组件 dispatch 的 Action。cold()— 描述期望的输出流每次订阅独立执行用来精确匹配 Effect 的发射结果。逐条解析5 个 Effects 的测试要点loadAll$带 startWith 的全量加载loadAll$使用startWith(loadAll())在订阅时立即触发一次加载所以即使actions$还没发射Effect 也会立刻请求index()。测试中只需验证输出时间线为--b第2帧发射成功 Action即可。load$按 id 查询单个联系人load$通过pluck(id)取出参数后调用show(id)。Mock Service 固定返回 id1 的 john因此期望的loadSuccess载荷也是 john 的数据——两者天然对齐。create$ / update$创建与更新这两条 Effect 结构类似区别在于create$额外挂了catchError处理失败场景。当前 Mock 不抛错所以测试只验证成功路径若需覆盖失败分支可让 Mock 返回throwError并断言输出failureAction。destroy$删除联系人destroy$先pluck(id)调destroy(id)再对返回值二次pluck(id)最终映射为removeSuccess({id})。测试重点在于确认时间线对齐和载荷正确。运行测试项目使用 Karma Jasmine 作为单元测试运行器。执行npm install npm test所有 Effects 测试将自动在 Chrome 中跑完控制台会列出每个it()用例的通过/失败状态。若某条时间线不匹配jasmine-marbles 会打印出差异对比定位问题非常快。最佳实践清单 一个 Effect 一个it()— 职责单一失败时立刻知道哪条流出了问题。Mock 数据与断言载荷保持一致— 如本文show()返回 john则loadSuccess的载荷也是 john避免巧合通过。时间线从第 0 帧对齐—hot和cold的前导-数量必须一致否则toBeObservable会因帧偏移而失败。避免在测试中引入真实网络— 始终用useClass/useValue替换 HTTP 和 Socket 依赖。扩展失败场景— 用cold(--#, {error: ...})描述报错流配合catchError断言failureAction 的发射。相关文件速查文件作用contacts-effects.ts5 条 HTTP Effect 3 条 Socket Effectcontacts-effects.spec.ts本文讲解的完整测试用例contacts-actions.ts全部 Action 工厂函数定义contacts-mock.service.ts测试专用 Mock返回固定联系人contacts.service.ts真实 HTTP 服务生产环境使用contacts-reducer.ts基于ngrx/entity的状态变更逻辑掌握以上内容你已具备对任意 NgRx Effects 编写 marble 测试的能力。/angular-contacts-app-example 的测试代码足够简洁可以直接作为新项目的 Effects 测试模板使用。【免费下载链接】angular-contacts-app-exampleFull Stack Angular PWA example app with NgRx NestJS项目地址: https://gitcode.com/gh_mirrors/an/angular-contacts-app-example创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考