FEATURED · 精选文章

Bitwarden Clients 测试规范:用 jest-mock-extended 的 mock\<T\>() 替代手写 Mock 实现

发布时间 / 2026/9/14 21:17:40
来源 / 创域科博编辑部
栏目 / 资讯中心
Bitwarden Clients 测试规范:用 jest-mock-extended 的 mock\<T\>() 替代手写 Mock 实现 Bitwarden Clients 测试规范用 jest-mock-extended 的 mockT() 替代手写 Mock 实现【免费下载链接】clientsBitwarden client apps (web, browser extension, desktop, and cli).项目地址: https://gitcode.com/GitHub_Trending/cl/clients导读本文基于仓库内 .claude/rules/testing.md 测试规则整理系统讲解 Bitwarden Clients 客户端仓库web、浏览器扩展、桌面端与 CLI中编写单元测试的核心约定优先使用jest-mock-extended的mockT()来模拟接口、抽象类与服务避免手写 partial mock。你将掌握mockT()与jest.fn()的选用边界、典型断言写法以及仓库内真实测试文件的落地范例能够直接写出符合该项目编码规范的 TypeScript 单元测试。规则背景ADR-0010 的落地.claude/rules/testing.md是该仓库面向所有*.spec.ts测试文件的统一约定frontmatter 中通过paths: - **/*.spec.ts声明其适用范围其内容源于 Bitwarden 官方架构决策记录 ADR-0010 — Clients Use Jest Mocks、apps/cli、apps/desktop、apps/web 及 bitwarden_license 下的企业版应用、libs 中的公共库统一采用 Jest 作为测试框架并使用jest-mock-extended提供强类型 Mock 能力。根目录 package.json 中锁定依赖版本jest-mock-extended: 4.0.1。整个仓库的测试配置由根目录 jest.config.js 统一管理它以 Nx 预设jest.preset.js为基础通过projects聚合了apps/下四个客户端应用、bitwarden_license/下企业版项目以及libs/下数十个公共库的独立 jest 配置默认开启覆盖率收集collectCoverage: true、collectCoverageFrom: [src/**/*.ts]并输出 HTML 与 LCOV 报告。核心约定优先使用mockT()规则原文要求使用jest-mock-extended提供的mockT()来 mock 接口interface、抽象类abstract class与服务service。它返回一个完全类型化fully-typed的 Mock并且接口中的每一个方法都会被自动 stub无需逐一手写空实现。规则文档中的最小示例import { mock } from jest-mock-extended; const cipherService mockCipherService(); const i18nService mockI18nService(); cipherService.get.mockResolvedValue(cipher); expect(i18nService.t).toHaveBeenCalledWith(itemDeleted);这段代码体现了两层能力创建即全量 stubmockCipherService()不需要像手写{ get: jest.fn(), ... }那样为每个成员补齐jest.fn()方法级行为定制与断言Mock 上的每个方法都是一个 jest MockFunction既可以调用mockResolvedValue(...)设置异步返回值也可以直接使用expect(...).toHaveBeenCalledWith(...)做调用断言。真实落地范例仓库中的mockT()用法服务层测试ExtensionLoginComponentServiceapps/browser/src/auth/popup/login/extension-login-component.service.spec.ts 是浏览器扩展登录服务的测试展示了对多个抽象服务批量创建 Mock 的典型写法import { MockProxy, mock } from jest-mock-extended; let cryptoFunctionService: MockProxyCryptoFunctionService; let environmentService: MockProxyEnvironmentService; let passwordGenerationService: MockProxyPasswordGenerationServiceAbstraction; let platformUtilsService: MockProxyBrowserPlatformUtilsService; let ssoLoginService: MockProxySsoLoginServiceAbstraction; let extensionAnonLayoutWrapperDataService: MockProxyExtensionAnonLayoutWrapperDataService; let ssoUrlService: MockProxySsoUrlService; beforeEach(() { cryptoFunctionService mockCryptoFunctionService(); environmentService mockEnvironmentService(); passwordGenerationService mockPasswordGenerationServiceAbstraction(); // ... });这里的MockProxyT是jest-mock-extended导出的类型别名用于声明「这是某个接口的强类型 Mock」与mockT()的返回值类型一致。之后这些 Mock 既可作为构造参数传入被测服务也可通过TestBed.configureTestingModule的 providers 以useValue注入到 Angular DI 容器中。测试中对异步方法的定制也直接使用 mock 方法链passwordGenerationService.generatePassword.mockResolvedValueOnce(state); passwordGenerationService.generatePassword.mockResolvedValueOnce(codeVerifier);随后用expect(ssoLoginService.setSsoState).toHaveBeenCalledWith(expectedState)断言调用参数用expect(platformUtilsService.launchUri).toHaveBeenCalled()断言副作用调用完整覆盖了「stub 行为 → 驱动被测方法 → 断言交互」的闭环。组件测试AccountSecurityComponentapps/browser/src/auth/popup/settings/account-security.component.spec.ts 是 Angular 组件测试的代表mock 的粒度覆盖了ApiService、PolicyService、CipherService、LogService、EnvironmentService、I18nService、DialogService等十多个抽象随后统一通过TestBedproviders 的{ provide: XxxService, useValue: xxxServiceMock }注入。这种写法在组件测试中大量复用保证被测组件仅依赖 Mock 提供的最小行为面。专项测试工具mockPorts 与 mockDeep在浏览器扩展的自动化填充autofill模块中apps/browser/spec/mock-port.spec-util.ts 展示了mockDeepT()的用法——它是jest-mock-extended提供的深度 Mock函数会递归 stub 嵌套对象的所有成员适合 mock 像chrome.runtime.Port这种带事件订阅机制的复杂结构import { mockDeep } from jest-mock-extended; const port mockDeepchrome.runtime.Port(); port.name portInfo.name; port.sender { url: chrome.runtime.getURL(), origin: chrome.runtime.getURL(), }; (port.postMessage as jest.Mock).mockImplementation((message) { (port.onMessage.addListener as jest.Mock).mock.calls.forEach(([callbackFn]) { callbackFn(message, port); }); });这里mockDeepchrome.runtime.Port()让postMessage、onMessage.addListener等深层成员全部自动变为 jest Mock之后通过(port.postMessage as jest.Mock)二次定制实现「消息广播」语义模拟真实 Port 的双向通信。另一个集中复用mockT()的测试夹具文件是 apps/browser/src/autofill/spec/autofill-mocks.ts其中以「工厂函数 customFields合并」模式如createAutofillFormMock(customFields {})批量生产默认数据对象供多个 spec 文件共享是「测试工具复用」的推荐做法。何时继续使用jest.fn()规则明确保留jest.fn()的使用场景ad-hoc 回调一次性回调与 spy间谍/监听器。典型如 apps/browser/src/auth/popup/login/extension-login-component.service.spec.ts 中对模块级函数的重定向jest.mock(../../../platform/flags, () ({ flagEnabled: jest.fn(), }));以及 apps/browser/src/auth/services/extension-two-factor-auth-component.service.spec.ts 中对 popup 关闭回调等一次性行为的 stubcloseSsoAuthResultPopout: jest.fn(), closeTwoFactorAuthWebAuthnPopout: jest.fn(), closeTwoFactorAuthEmailPopout: jest.fn(), closeTwoFactorAuthDuoPopout: jest.fn(),规则给出的判据非常清晰当你发现自己即将为一个带类型的接口手写 partial 实现时就应该改用mockT()只有jest.fn()更贴合临时回调/spy 语义时才保留它。选择准则速查场景推荐写法理由Mock 一个接口 / 抽象类 / 服务mockT()或mockDeepT()全量自动 stub类型完整无需手写 partial为复杂嵌套对象如chrome.runtime.Port递归生成 MockmockDeepT()深层成员同样被 stub可二次定制一次性回调、监听器、spy 桩jest.fn()语义贴合无类型骨架需要补齐断言某方法被调用及参数expect(mock.method).toHaveBeenCalledWith(...)Mock 方法本身即 jest MockFunction定制异步方法返回值mock.method.mockResolvedValue(...)/mockResolvedValueOnce(...)直接链式调用组合实践Mock 真实依赖混合注入仓库测试并不排斥「Mock 与真实依赖混用」。例如 apps/browser/src/auth/popup/login/extension-login-component.service.spec.ts 中被测服务本身通过new ExtensionLoginComponentService(...)工厂方式构造全部依赖为 Mock但 Observable 属性如environmentService.environment$会赋值为真实的BehaviorSubject以驱动异步数据流environmentService.environment$ new BehaviorSubjectEnvironment({ getWebVaultUrl: () baseUrl, } as Environment);这种「Mock 方法 真实响应式数据源」的组合既保证了隔离性又不牺牲对 RxJS 异步链路的覆盖能力。结合根目录 jest.config.js 中maxWorkers: 8、workerIdleMemoryLimit: 1500MiB等 CI 友好配置整个仓库形成了一套「强类型 Mock 为主、jest.fn() 为辅、Nx 聚合配置」的规模化测试实践。总结Bitwarden Clients 的测试规范以一句话即可概括凡是要模拟带类型的接口、抽象类或服务一律使用mockT()jest.fn()只留给临时回调与 spy。这套约定通过 .claude/rules/testing.md 作用于仓库内所有*.spec.ts在浏览器扩展登录/SSO/2FA、autofill 后台服务、账号安全设置组件等大量测试中均有真实落地可参考 extension-login-component.service.spec.ts、account-security.component.spec.ts、mock-port.spec-util.ts。对任何 Bitwarden Clients 的贡献者而言遵循该规则即可写出类型安全、低样板代码且可维护的单元测试。【免费下载链接】clientsBitwarden client apps (web, browser extension, desktop, and cli).项目地址: https://gitcode.com/GitHub_Trending/cl/clients创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻