Angular测试报错:Hooks不可在测试内定义,beforeEach嵌套于测试用例
测试ServiceA时触发钩子嵌套错误的解决办法
问题背景
我需要测试名为ServiceA的服务,其代码如下:
export class ServiceA { constructor(protected serviceB: ServiceB) {} // 此处省略更多代码 }
ServiceA依赖ServiceB,ServiceB依赖ServiceC,而ServiceC依赖注入令牌SYSTEM_NAME,代码如下:
@Injectable({ providedIn: 'root' }) export class ServiceC { constructor(@Inject(SYSTEM_NAME) private systemName:string) {} // 此处省略更多代码 }
为测试ServiceA,我创建了两个服务工厂:一个用于创建ServiceC(供ServiceB依赖),另一个用于创建ServiceA。但调用createServiceA(serviceB)时出现以下错误:
Error: Hooks cannot be defined inside tests. Hook of type "beforeEach" is nested within "should create an instance".
测试代码如下:
let spectatorServiceC: SpectatorService<ServiceC>; let spectatorServiceA: SpectatorService<ServiceA>; let serviceB: ServiceB; describe('ServiceA', () => { const createServiceC = createServiceFactory({ service: ServiceC, providers: [ { provide: SYSTEM_NAME, useValue: SYSTEM_NAME_VALUE } ], }); const createServiceA = (serviceB: ServiceB) => createServiceFactory({ service: ServiceA, providers: [ { provide: ServiceB, useValue: serviceB }, ServiceC ], }) as any; beforeEach(() => { spectatorServiceC = createServiceC(); serviceB = new ServiceB(spectatorServiceC.service); spectatorServiceA = createServiceA(serviceB); // 添加此行后触发错误 }); it('should create an instance', () => { expect(serviceB.service).toBeTruthy(); }); })
问题原因
createServiceFactory内部会自动注册测试钩子(如beforeEach),你在beforeEach函数内部调用createServiceA(它又调用了createServiceFactory),导致钩子嵌套定义,触发框架的错误提示。
解决方案
不要在beforeEach或测试用例(it)内部调用createServiceFactory,应将工厂创建逻辑移到describe块的顶层,再在beforeEach中使用工厂创建实例。同时,优化依赖注入方式,避免重复声明依赖:
方案1:手动传入ServiceB实例
let spectatorServiceC: SpectatorService<ServiceC>; let spectatorServiceA: SpectatorService<ServiceA>; let serviceB: ServiceB; describe('ServiceA', () => { // 将工厂定义在describe顶层 const createServiceC = createServiceFactory({ service: ServiceC, providers: [ { provide: SYSTEM_NAME, useValue: SYSTEM_NAME_VALUE } ], }); const createServiceA = createServiceFactory({ service: ServiceA, providers: [] // 先不指定ServiceB,留到创建实例时传入 }); beforeEach(() => { spectatorServiceC = createServiceC(); serviceB = new ServiceB(spectatorServiceC.service); // 创建ServiceA实例时传入自定义的ServiceB依赖 spectatorServiceA = createServiceA({ providers: [{ provide: ServiceB, useValue: serviceB }] }); }); it('should create an instance', () => { expect(spectatorServiceA.service).toBeTruthy(); expect(serviceB.service).toBeTruthy(); }); })
方案2:复用依赖让DI自动创建ServiceB
如果不需要手动控制ServiceB的创建,可以直接复用ServiceC的依赖,让依赖注入系统自动处理ServiceB的实例化:
let spectatorServiceA: SpectatorService<ServiceA>; describe('ServiceA', () => { const createServiceC = createServiceFactory({ service: ServiceC, providers: [ { provide: SYSTEM_NAME, useValue: SYSTEM_NAME_VALUE } ], }); // 复用ServiceC的依赖,同时声明ServiceB,让DI自动创建实例 const createServiceA = createServiceFactory({ service: ServiceA, providers: [ServiceB, ...createServiceC.providers] }); beforeEach(() => { spectatorServiceA = createServiceA(); }); it('should create an instance', () => { expect(spectatorServiceA.service).toBeTruthy(); }); })
内容的提问来源于stack exchange,提问作者Iris
相关产品推荐
相关产品推荐

