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

请求解决Jasmine中spyOn无法找到get()对象的测试错误

解决Angular测试中spyOn报错:could not find an object to spy upon for get()

错误原因

你触发的错误是因为TestBed.inject(ApiService)获取到的不是Jasmine可识别的间谍对象(SpyObj),直接调用spyOn时,Jasmine找不到可以挂载间谍的目标方法。

解决方案

方法1:在TestBed配置阶段预创建SpyObj(推荐)

在测试初始化阶段就把ApiService替换成SpyObj,这样后续注入的就是可被监听的间谍对象:

describe('blah blah blah', () => {
  let apiService: jasmine.SpyObj<ApiService>;
  let component: YourComponent; // 替换成你的组件类名
  let fixture: ComponentFixture<YourComponent>;

  beforeEach(() => {
    // 创建包含需要监听方法的SpyObj
    const apiSpy = jasmine.createSpyObj('ApiService', ['get', 'delete']); // 根据实际方法调整

    TestBed.configureTestingModule({
      declarations: [YourComponent],
      providers: [
        { provide: ApiService, useValue: apiSpy } // 用SpyObj替代真实服务
      ]
    });

    // 注入SpyObj
    apiService = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
    fixture = TestBed.createComponent(YourComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  fit('click confirm delete should delete the asset', fakeAsync(() => {
    // 直接给SpyObj的方法设置返回值
    apiService.get.and.returnValue(of({entity: ASSET} as unknown as HttpResponse<null>));

    component.reload();
    fixture.detectChanges();

    // ... 此处添加点击删除按钮的触发逻辑(比如fixture.debugElement.query(By.css('.delete-btn')).triggerEventHandler('click', null);)

    expect(component.asset).toBeFalsy();
    expect(apiService.get).toHaveBeenCalled();
  }));
});

方法2:测试用例内动态替换为SpyObj(适合特殊场景)

如果需要在单个测试用例中临时替换服务实例,可直接创建SpyObj并赋值给组件的服务引用:

describe('blah blah blah', () => {
  let apiService: jasmine.SpyObj<ApiService>;
  let component: YourComponent;
  let fixture: ComponentFixture<YourComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [YourComponent],
      providers: [ApiService] // 先注入真实服务,后续替换
    });

    fixture = TestBed.createComponent(YourComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  fit('click confirm delete should delete the asset', fakeAsync(() => {
    // 创建新的SpyObj并替换组件内的服务引用
    apiService = jasmine.createSpyObj('ApiService', ['get']);
    component.apiService = apiService; // 假设组件通过属性持有ApiService实例

    apiService.get.and.returnValue(of({entity: ASSET} as unknown as HttpResponse<null>));

    component.reload();
    fixture.detectChanges();

    // ... 点击删除按钮的逻辑

    expect(component.asset).toBeFalsy();
    expect(apiService.get).toHaveBeenCalled();
  }));
});

关键注意点

  • 只有当服务实例是Jasmine SpyObj时,spyOn才能正常工作,不要对TestBed.inject获取的真实服务实例直接调用spyOn。
  • 推荐使用方法1,在beforeEach中统一配置SpyObj,提升测试用例的复用性和可维护性。
  • 若组件通过构造函数注入ApiService,必须在TestBed配置中用SpyObj替换真实服务,否则组件初始化时会拿到真实实例,无法监听。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 11:35:44