Angular中用Jasmine测试含服务调用的ngOnInit全代码覆盖方法
ngOnInit全代码覆盖的测试实现思路
ngOnInit里后续的逻辑是订阅Router的paramMap可观察流,只要流没有主动推送值,订阅回调内的所有代码都不会执行,自然无法达到代码覆盖要求。要实现100%行覆盖,核心是手动控制paramMap的推送值,把if/else两个分支全部触发执行。
前置Mock配置
在编写测试用例前,需要在spec文件的beforeEach钩子里准备好可控制的依赖Mock,重点是把Router的paramMap改造为可以手动推送值的流:
// 引入需要的依赖 import { Subject } from 'rxjs'; import { ParamMap } from '@angular/router'; // 定义可手动控制参数推送的流 const paramMapSubject = new Subject<ParamMap>(); beforeEach(() => { // 给Router创建Spy,让paramMap返回我们自定义的可观察流 router = jasmine.createSpyObj('Router', [], { paramMap: paramMapSubject.asObservable() }); // 其余组件初始化逻辑保持原有写法 TestBed.configureTestingModule({/* 原有配置保持不变 */}).compileComponents(); fixture = TestBed.createComponent(YourComponent); component = fixture.componentInstance; });
测试用例补全
在已有的component.ngOnInit()调用之后,按照以下顺序补全内容,即可覆盖所有代码行:
- 验证第一行的服务调用逻辑
// 确认resetCurrentMenu方法被正常触发 expect(componentInteractionService.resetCurrentMenu).toHaveBeenCalled(); - 触发第一个代码分支(
contentTitle为undefined,走URL自动截取标题的逻辑)// 手动向paramMap流推送不带contentTitle的测试参数 paramMapSubject.next({ get: (key: string) => { const paramStore = { currentContentUrl: '/system/user/user-list', contentSubtitle: '系统管理模块' // 故意不设置contentTitle字段,让get方法返回undefined,触发if分支 }; return paramStore[key] as string | undefined | null; } } as ParamMap); // 断言分支逻辑执行正确 expect(component.currentContentUrl).toBe('/system/user/user-list'); expect(component.contentSubstitle).toBe('系统管理模块'); // 验证自动截取URL最后一段作为标题的逻辑 expect(component.contentTitle).toBe('user-list'); - 触发第二个代码分支(
contentTitle有值,走自定义标题的逻辑)// 再次向paramMap流推送带contentTitle的测试参数 paramMapSubject.next({ get: (key: string) => { const paramStore = { currentContentUrl: '/system/role/role-config', contentSubtitle: '权限配置模块', contentTitle: '自定义角色管理' }; return paramStore[key] as string | undefined | null; } } as ParamMap); // 断言else分支的逻辑执行正确 expect(component.currentContentUrl).toBe('/system/role/role-config'); expect(component.contentSubstitle).toBe('权限配置模块'); expect(component.contentTitle).toBe('自定义角色管理');
关键注意点
- 不要依赖真实路由的参数传值,手动控制
paramMap的推送值才能稳定触发订阅回调,避免出现代码覆盖不全的问题 - 必须分别推送两种不同结构的参数,把if块和else块的代码都执行一次,才能达成全代码覆盖的要求
- 这种手动推送流的写法,也可以覆盖路由参数动态变化时组件的响应逻辑
内容的提问来源于stack exchange,提问作者Dhritiman Tamuli Saikia
相关产品推荐
相关产品推荐

