Angular 测试实战指南ECC 规则体系下的组件、服务与路由测试全解析【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC本文基于 ECC 仓库中的 Angular 语言级测试规则文档docs/ja-JP/rules/angular/testing.md英文原版见 rules/angular/testing.md展开系统讲解 Angular 项目中组件测试、Signal 输入、组件 Harness、路由测试、异步/HTTP 测试与 E2E 测试的完整方法论并结合仓库内angular-developer技能参考文档与通用测试规则进行源码级印证。读完本文你将掌握一套可直接复制到实际 Angular 项目中的测试骨架、命令与覆盖策略。规则定位这份文档管什么该规则文档通过 frontmatter 声明了生效范围paths: - **/*.spec.ts - **/*.test.ts即所有*.spec.ts与*.test.ts测试文件都属于该规则的管辖范围。文档开头明确说明它是对通用测试规则的 Angular 专属扩展对应文件为 docs/ja-JP/rules/common/testing.md英文版见 rules/common/testing.md。这意味着 Angular 测试除了遵循本文件的专属约定外还必须同时满足通用测试规则中关于最低 80% 覆盖率、测试驱动开发TDD工作流与AAA 测试结构的硬性要求。在 ECC 的规则体系里rules/angular/目录下还并列存放着coding-style.md、hooks.md、patterns.md、security.md本测试规则与它们共同构成完整的 Angular 开发约束更深入的测试模式、Harness 用法与异步最佳实践则由技能angular-developer见 skills/angular-developer/SKILL.md提供支撑本文后面的内容会持续交叉引用这些参考文档。测试运行器先确认项目配置再决定命令Angular 生态中测试运行器并不唯一。规则要求使用项目已配置好的运行器而不是自行引入新框架。判断依据是两个文件angular.json查看 builder 配置如angular-devkit/build-angular:vitest、karma等package.json查看scripts段与 devDependencies 中安装的是 Vitest、Jest 还是 Jasmine Karma。Angular 项目中最常见的三种选择是Vitest、Jest和Jasmine Karma。无论底层是哪一种CLI 入口通常统一为ng test # 监听模式watch开发时使用 ng test --no-watch # CI 模式跑完即退出从 skills/angular-developer/references/testing-fundamentals.md 可以印证同样原则测试应使用项目已配置的 runner。在 CI 流水线中务必使用--no-watch避免进程因监听而永不退出导致流水线挂起。TestBed 配置与组件夹具组件测试的核心入口是TestBed。对于Standalone 组件直接在imports中导入组件类本身即可无需再声明模块describe(UserCardComponent, () { let fixture: ComponentFixtureUserCardComponent; beforeEach(async () { await TestBed.configureTestingModule({ imports: [UserCardComponent], }).compileComponents(); fixture TestBed.createComponent(UserCardComponent); }); });规则特别提醒对于使用外部模板external template的组件必须调用compileComponents()等待模板与样式编译完成后再创建夹具Standalone 组件若模板内联也可省略但统一调用更稳妥。创建后的ComponentFixture提供三个常用访问入口fixture.componentInstance组件类实例可直接访问属性和方法fixture.nativeElement组件根 DOM 元素fixture.debugElementAngular 的 DebugElement 包装提供query(By.css(...))等平台无关的查询方式参见 testing-fundamentals.md。异步优先的测试哲学testing-fundamentals.md强调现代 Angular 应用常以异步方式调度状态更新尤其在引入 Signal 或 zoneless 变更检测后测试必须主动等待。推荐的模式是Act–Wait–AssertAct更新状态或执行动作设置输入、点击按钮Waitawait fixture.whenStable()让框架处理完排队的更新并完成渲染Assert对结果做断言。it(should display the default title, async () { // ACT组件以默认状态创建 // WAIT等待初始数据绑定完成 await fixture.whenStable(); // ASSERT expect(h1.textContent).toContain(Default Title); });Signal 输入的测试方式Angular Signal 化的组件输入input()不能再通过直接赋值属性来设置规则明确要求使用fixture.componentRef.setInput()fixture.componentRef.setInput(user, mockUser); fixture.detectChanges();setInput()走的是与真实模板绑定相同的输入通道会正确触发 Signal 的写入与下游计算更新随后调用detectChanges()将新值反映到视图中。这是测试 Signal 输入组件的标准姿势比操作componentInstance更贴近真实运行语义。组件 Harness优先于直接 DOM 查询规则给出了一个明确的取舍UI 交互测试优先使用 Angular CDK 组件 Harness而不是手写querySelector。理由是 Harness 对标记markup变更具有更强的耐性——重构内部 HTML 或 CSS 类时测试不会跟着碎掉。组件 Harness 的三重价值详见 component-harnesses.md健壮性不因组件内部 DOM 结构调整而失效可读性以用户视角描述交互如button.click()、slider.getValue()而非querySelector链可复用性同一套 Harness 可同时用于单元测试与 E2E 测试。在单元测试中通过TestbedHarnessEnvironment获取 loaderimport { HarnessLoader } from angular/cdk/testing; import { TestbedHarnessEnvironment } from angular/cdk/testing/testbed; import { MatButtonHarness } from angular/material/button/testing; let loader: HarnessLoader; beforeEach(() { loader TestbedHarnessEnvironment.loader(fixture); }); it(triggers save on button click, async () { const button await loader.getHarness(MatButtonHarness.with({ text: Save })); await button.click(); expect(saveSpy).toHaveBeenCalled(); });几个关键概念HarnessLoader查找并创建 Harness 实例的入口通过TestbedHarnessEnvironment.loader(fixture)获得loader.getHarness(HarnessClass)异步返回第一个匹配组件的 Harness 实例HarnessClass.with({...})多数 Harness 提供静态with方法返回HarnessPredicate可基于文本、selector、禁用状态等属性精确定位目标组件Harness API.click()、.getText()、.getValue()等方法内部会自动处理异步等待与变更检测测试代码无需手动detectChanges。路由测试RouterTestingHarness 而非 mock Router对依赖路由的组件规则推荐使用RouterTestingHarness而不是 mock 掉Router服务。核心原因是使用真实 harness 才能测试到实际的路由配置、守卫guards与解析器resolvers测试才有意义参见 router-testing.md。配合provideRouter在 TestBed 中提供测试专用路由import { RouterTestingHarness } from angular/router/testing; it(renders user on navigation, async () { const harness await RouterTestingHarness.create(); const component await harness.navigateByUrl(/users/1, UserDetailComponent); expect(component.userId()).toBe(1); });完整用法要点provideRouter([...])在TestBed.configureTestingModule的providers中注入测试路由表RouterTestingHarness.create()异步创建 harness 并完成到根路径/的首次导航harness.navigateByUrl(url, ComponentType)模拟导航Promise 解析为激活后的组件实例harness.router.url访问真实 Router 实例断言当前 URL导航动作后记得await harness.fixture.whenStable()等待路由完成再断言。异步测试fakeAsync 与 waitForAsync 的取舍规则给出两种异步策略的使用边界受控异步用fakeAsynctick可精确控制时间推进真实异步用waitForAsyncfixture.whenStable()适合真实计时器或真实异步任务。it(loads user after delay, fakeAsync(() { const service TestBed.inject(UserService); vi.spyOn(service, getUser).mockReturnValue(of(mockUser)); fixture.detectChanges(); tick(); fixture.detectChanges(); expect(fixture.nativeElement.querySelector(.name).textContent).toBe(mockUser.name); }));注意示例中的vi.spyOn表明它面向 Vitest 运行器若项目使用 JasmineKarma或 Jest将vi.前缀替换为对应的spyOn语法即可。tick()会同步推进fakeAsync区域内的定时器/微任务随后再次detectChanges()完成渲染最终对 DOM 文本做断言。HTTP 测试HttpTestingController 模拟请求通过provideHttpClientTesting()启用 Angular 的 HTTP 测试后端并用HttpTestingController手动断言请求import { provideHttpClientTesting } from angular/common/http/testing; import { HttpTestingController } from angular/common/http/testing; beforeEach(() { TestBed.configureTestingModule({ providers: [provideHttpClient(), provideHttpClientTesting()], }); httpMock TestBed.inject(HttpTestingController); }); afterEach(() httpMock.verify());两个容易踩坑的点必须同时提供provideHttpClient()真实 HttpClient 的基础能力与provideHttpClientTesting()测试后端二者缺一不可每个用例结束后调用httpMock.verify()它会断言没有未处理的意外请求防止测试之间互相污染。服务测试无需组件夹具直接注入服务Service的测试不需要创建任何组件夹具直接在 TestBed 中声明 provider 并注入describe(UserService, () { let service: UserService; beforeEach(() { TestBed.configureTestingModule({ providers: [provideHttpClient(), provideHttpClientTesting()], }); service TestBed.inject(UserService); }); });若服务内部依赖 HttpClient同样需要provideHttpClient()provideHttpClientTesting()组合。这种直注方式让服务的每个公共方法都能被独立验证配合 80% 覆盖率要求是整套规则中最基础也最重要的测试形态。测试对象清单什么该测、怎么测对象测试要点测试形态服务所有公共方法、错误路径、HTTP 交互TestBed 直注 HttpTestingController组件输入/输出绑定、关键状态的渲染结果、Harness 驱动的用户交互TestBed ComponentFixture Harness管道纯函数变换普通单元测试无需 TestBed守卫/解析器允许与拒绝状态下各自的返回值RouterTestingHarness驱动其中管道Pipe是特例它是纯函数直接new出来传参断言即可完全不需要引入 TestBed测试成本最低。E2E 测试真实浏览器中的关键用户流关键用户流程登录、下单、支付等使用项目配置的 E2E 框架常见为Cypress或Playwright详见 e2e-testing.md。运行命令以项目实际配置为准常见有npm run e2e、pnpm e2e或ng e2e。Cypress 示例与规则文档一致describe(Login flow, () { it(redirects to dashboard on valid credentials, () { cy.visit(/login); cy.get([data-cyemail]).type(userexample.com); cy.get([data-cypassword]).type(password123); cy.get([data-cysubmit]).click(); cy.url().should(include, /dashboard); }); });E2E 的两条硬性纪律为可交互元素添加data-cy属性作为稳定选择器不要依赖 CSS 类名或文本内容做选择器——它们极易随样式与文案调整而失效。若项目使用 Playwright则更推荐无障碍定位器getByRole、getByLabel或稳定的data-*属性并等待特定 UI 状态/路由/网络响应而非固定 sleep见 e2e-testing.md。另外保持冒烟测试短小把完整流程覆盖留给价值最高的路径。覆盖率与通用质量门禁规则的覆盖率底线继承自通用测试规则 rules/common/testing.md服务与管道目标 ≥80% 覆盖率组件测试行为而非实现细节test behaviour, not implementation details——不要为了凑覆盖率去断言内部私有方法或中间状态。通用规则还强制 TDD 工作流RED → GREEN → IMPROVE与AAA 结构Arrange–Act–Assert并给出了行为化的命名规范test(returns empty array when no markets match query, () {}) test(throws error when API key is missing, () {}) test(falls back to substring search when Redis is unavailable, () {})遇到测试失败时按通用规则依次排查先借助tdd-guideagent再检查测试隔离性与 mock 正确性最后遵循修复实现而非测试除非测试本身写错了的原则。与 ECC 规则体系的协同查阅通用测试基线覆盖率/TDD/AAArules/common/testing.mdAngular 测试规则日文版docs/ja-JP/rules/angular/testing.mdAngular 开发者技能入口skills/angular-developer/SKILL.md其中与测试直接相关的参考文档包括testing-fundamentals.mdTestBed、异步模式、Act–Wait–Assertcomponent-harnesses.mdHarness 原理与 HarnessPredicaterouter-testing.mdRouterTestingHarness 与 provideRoutere2e-testing.mdCypress/Playwright 最佳实践总结一份可直接落地的 Angular 测试清单先看配置以angular.json与package.json为准选择 runner用ng testwatch/ng test --no-watchCI组件测试Standalone 组件直接imports外部模板必须compileComponents()Signal 输入用fixture.componentRef.setInput()交互测试优先 CDK HarnessTestbedHarnessEnvironmentwith({...})谓词拒绝脆弱 DOM 查询路由相关用RouterTestingHarnessprovideRouter不要 mock Router同时覆盖守卫/解析器的放行与拒绝分支异步与 HTTPfakeAsynctick控制时序provideHttpClientTesting()HttpTestingController.verify()守护请求服务/管道服务直注测试公共方法与错误路径管道做纯函数单测E2E关键流程交给 Cypress/Playwright坚持data-cy稳定选择器覆盖率服务与管道 ≥80%组件测行为不测实现全程遵循 TDD 与 AAA。这套规则同时约束着 Agent 与人类开发者既保证了 Angular 测试的规范统一也让测试代码本身具备高可维护性——这正是 ECC 将语言级测试规则沉淀为仓库知识的价值所在。【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考