You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular单元测试报错:Expected spy get to have been called排查求助

Angular Component1单元测试Spy未触发问题

错误现象

编写Component1的单元测试时,两个测试用例均返回相同错误:

Error: Expected spy get to have been called.
    at <Jasmine>
    at UserContext.apply (src/app/features/home/home.component.spec.ts:70:37)
    at _ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:409:30)
    at ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/zone-testing.js:303:43)

组件代码明确调用了service2.get(0),但测试中对service1.get的Spy始终未触发,尝试多种Spy创建方式均无效。

单元测试代码

const mockActiveService1 = {
  .......
}
const mockNotActiveService1 = {
  .......
}

describe('Component1 ', () => {
  let component: Component1 ;
  let fixture: ComponentFixture<Component1>;

  beforeEach(async () => {
    TestBed.configureTestingModule({
      declarations: [Component1],
      providers: [
        { provide: Service1, useValue: mockActiveService1 }
      ],
      imports: [HttpClientTestingModule, ToastrModule.forRoot()]
    }).compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(Component1);
    component = fixture.componentInstance;
    service1 = TestBed.inject(Service1); // 修正原代码的TestBeb拼写错误
  });


it('should load the current dataService2', async () => {
  spyOn(service1, 'get').and.returnValue(of(mockActiveService1));
  
  fixture.detectChanges();

  await component.ngOnInit();

  expect(service1.get).toHaveBeenCalled();
  expect(component.dataService2).toEqual(mockActiveService1);
  expect(component.showCountdown).toBeFalse();
  expect(component.loading).toBeFalse();
});

it('should show info message and navigate to default route when there is no active dataService2', fakeAsync(() => {
  const toastrServiceSpy = spyOn(toastrServiceMock, 'info');
  const routerSpy = spyOn(routerMock, 'navigate');

  const getSpy = spyOn(service1, 'get').and.callThrough().and.returnValue(of(mockNotActiveService1));

  fixture.detectChanges();
  component.ngOnInit();
  tick();

  expect(getSpy).toHaveBeenCalled();
  expect(toastrServiceSpy).toHaveBeenCalledWith('no active dataService2', 'Info!');
  expect(routerSpy).toHaveBeenCalledWith(['/default']);
}));

组件核心代码

ngOnInit(): void {
    this.loading = true;
    this.showCountdown = false;
    this.loadCurrentdataService2();
}
loadCurrentdataService2(): void {
    this.service2.get(0).subscribe(results => {
        if (results) {
            this.dataService2= results;

            if (this.dataService2 && this.dataService2.isActive) {
...............

调试尝试

在测试中添加日志查看调用情况:

it('should load the current dataService2', fakeAsync(() => {
    spyOn(service1, 'get').and.callThrough();

    fixture.detectChanges();

    component.ngOnInit();
    tick();

    console.log('service1.get.calls', (service1.get as any).calls);

    expect(service1.get).toHaveBeenCalled();
    expect(component.dataService2).toEqual(mockActiveService1);
    expect(component.showCountdown).toBeFalse();
    expect(component.loading).toBeFalse();
  }));

输出结果:

LOG: 'service1.get.calls', CallTracker{track: function(context) { ... }, any: function() { ... }, count: function() { ... }, argsFor: function(index) { ... }, thisFor: function(index) { ... }, all: function() { ... }, allArgs: function() { ... }, first: function() { ... }, mostRecent: function() { ... }, reset: function() { ... }, saveArgumentsByValue: function() { ... }}

同时尝试用callFake创建Spy:

spyOn(service1, 'get').and.callFake(() => {
return of(mockActiveService1);
});

问题依旧。

排查思路及解决建议

  • 核对服务依赖匹配:组件调用的是service2.get,但测试Spy的是service1.get,确认Service1与Service2是否为同一服务,或组件是否注入了错误的服务实例。若组件依赖Service2,测试却提供并SpyService1,必然无法触发。
  • 修正测试拼写错误:原测试中service1 = TestBeb.inject(Service1);存在拼写错误,应为TestBed.inject,该错误会导致service1未正确获取实例,Spy无效。
  • 调整Spy创建时机:确保在component.ngOnInit()或fixture.detectChanges()之前创建Spy,否则组件初始化时调用的服务方法无法被Spy捕获。比如第一个测试先调用fixture.detectChanges()再创建Spy,此时ngOnInit已执行,Spy不会生效。
  • 检查mock对象方法定义:确认mockActiveService1和mockNotActiveService1是否定义了get方法,若mock对象无该方法,spyOn(service1, 'get')会失败,导致Spy未正确创建。
  • 修正异步处理逻辑:第一个测试使用async/await,但ngOnInit内的loadCurrentdataService2是订阅Observable,await component.ngOnInit()不会等待订阅完成,建议改用fakeAsync/tick或async/fixture.whenStable()处理异步操作。

内容的提问来源于stack exchange,提问作者Kenzo_Gilead

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 11:54:51