如何用Jest/Angular Testing Library测试EventEmitter订阅分支?
测试覆盖方案&参考资料
一、覆盖订阅逻辑与if分支的测试代码实现
1. 搭建测试基础环境
首先需要模拟NgbModalService和模态框实例,无需真实渲染组件,只需验证逻辑交互即可。以下是完整测试框架:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { YourComponent } from './your.component'; // 替换为你的组件类名 import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { EventEmitter } from '@angular/core'; // 自定义模拟模态框引用类 class MockModalRef implements Partial<NgbModalRef> { componentInstance = { confirmMessage: '', emitService: new EventEmitter<boolean>() }; } describe('YourComponent', () => { let component: YourComponent; let modalService: jest.Mocked<NgbModal>; let mockModalRef: MockModalRef; beforeEach(async () => { // 模拟NgbModal服务 const modalMock = { open: jest.fn(() => new MockModalRef()) }; await TestBed.configureTestingModule({ declarations: [YourComponent], providers: [{ provide: NgbModal, useValue: modalMock }] }).compileComponents(); component = TestBed.createComponent(YourComponent).componentInstance; modalService = TestBed.inject(NgbModal) as jest.Mocked<NgbModal>; mockModalRef = modalService.open.mock.results[0].value as MockModalRef; // 提前mock删除方法,方便后续验证调用 jest.spyOn(component, 'deleteIndividualCertById').mockImplementation(() => {}); });
2. 测试确认删除分支(触发if条件)
该测试覆盖用户确认删除的场景,验证订阅事件触发后删除方法是否被正确调用:
it('calls deleteIndividualCertById when delete is confirmed', () => { const testId = 123; component.openDeleteModal(testId); // 模拟模态框的确认事件 mockModalRef.componentInstance.emitService.next(true); // 验证核心逻辑 expect(component.deleteIndividualCertById).toHaveBeenCalledWith(testId); expect(modalService.open).toHaveBeenCalledWith( expect.any(Function), // 对应DeleteConfirmComponent { size: 'lg', backdrop: 'static', centered: true } ); expect(mockModalRef.componentInstance.confirmMessage).toBe( "Are you sure you wish to delete this Certification?" ); });
3. 测试取消删除分支(不触发if条件)
该测试覆盖用户取消删除的场景,验证删除方法不会被调用:
it('does NOT call deleteIndividualCertById when delete is cancelled', () => { const testId = 456; component.openDeleteModal(testId); // 模拟模态框的取消事件 mockModalRef.componentInstance.emitService.next(false); // 验证删除方法未被调用 expect(component.deleteIndividualCertById).not.toHaveBeenCalled(); }); });
以上代码可完整覆盖openDeleteModal中的订阅逻辑和if分支的两种情况。
二、Jest + Angular Testing Library 实用参考要点
核心原则
始终围绕用户真实操作编写测试,而非直接调用组件方法(纯逻辑方法除外)。例如组件中有触发openDeleteModal的“删除”按钮时,可模拟真实点击流程:
import { render, screen } from '@testing-library/angular'; it('triggers delete flow when delete button is clicked', async () => { // 渲染组件 await render(YourComponent); // 点击页面上的删除按钮 await screen.getByRole('button', { name: /delete certification/i }).click(); // 点击模态框内的确认按钮 await screen.getByRole('button', { name: /confirm/i }).click(); // 验证删除方法被调用 expect(component.deleteIndividualCertById).toHaveBeenCalled(); });
Jest 实用技巧
- 用
jest.spyOn快速模拟组件或服务方法,可通过mockRestore()恢复原始实现 - 用
jest.mock批量模拟第三方库(如@ng-bootstrap/ng-bootstrap),减少重复配置 - 在
beforeEach中用jest.clearAllMocks()清除mock调用记录,避免测试间污染
Angular Testing Library 关键方法
screen.getByRole:按角色查询DOM元素(优先使用,符合无障碍测试标准)screen.getByText:按文本内容查询元素await ...click():模拟用户点击操作,自动等待页面状态更新
内容的提问来源于stack exchange,提问作者balaso
相关产品推荐
相关产品推荐

