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

Angular混合项目单元测试Mock服务类问题求助

Angular混合项目单元测试:NullInjectorError问题解决

执行ng test时遇到如下错误:

Chrome 111.0.0.0 (Windows 10) GoComponent should create FAILED
        NullInjectorError: R3InjectorError(DynamicTestModule)[ABCadminService -> ApiconfigurationService -> ng1ServiceProviderUpgrade -> ng1ServiceProviderUpgrade]:
          NullInjectorError: No provider for ng1ServiceProviderUpgrade!
        error properties: Object({ ngTempTokenPath: null, ngTokenPath: [ 'ABCadminService', 'ApiconfigurationService', 'ng1ServiceProviderUpgrade', 'ng1ServiceProviderUpgrade' ] })
        NullInjectorError: R3InjectorError(DynamicTestModule)[ABCadminService -> ApiconfigurationService -> ng1ServiceProviderUpgrade -> ng1ServiceProviderUpgrade]:
          NullInjectorError: No provider for ng1ServiceProviderUpgrade!
            at NullInjector.get (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:11100:27)

相关代码

component.spec.ts

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

  beforeEach(async () => {
    mockABCadminService = jasmine.createSpyObj(['getABC']);
    mockABCadminService.getABC.and.returnValue('abc');
    TestBed.configureTestingModule({
      imports: [HttpClientModule],
      declarations: [GoComponent],
      providers: [
        { provide: ABCadminService, useValue: mockABCadminService }
      ]
    })
      .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(GoComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

service.ts

@Injectable({
    providedIn: 'root'
})

export class ABCadminService {
    private apiURL: string;
    private baseUrl: string = '/abcadmin';
    private url: string;
    constructor(
        private http: HttpClient,
        private apiConfig: ApiconfigurationService
    ) {
        this.apiURL = this.apiConfig.getApiUrl();
        this.url = this.apiURL + this.baseUrl;
    }

    getABC(): Observable<abcTree> {
        return this.http.get<abcTree>(this.url);
    }
}

component.ts

export class GoComponent implements OnInit {

  contentLoading: boolean = false;
  content: string = '';

  constructor(private abcadminService: ABCadminService) { }

  ngOnInit(): void {
      this.contentLoading = true;
      this.abcadminService.getABC().subscribe(data => {
          this.content = data;
          this.contentLoading = false;
    })
  }
}

问题分析与解决

你不需要Mock整个依赖链,问题出在Mock的ABCadminService没有正确覆盖真实服务,导致TestBed仍尝试实例化真实的ABCadminService,进而触发其依赖ApiconfigurationService的注入,最终因为混合项目的AngularJS升级服务ng1ServiceProviderUpgrade未提供而报错。

修复步骤

  1. 确保Mock返回Observable:真实的getABC方法返回Observable,组件中会调用subscribe,所以Mock必须返回Observable类型的值,而非字符串。
  2. 强制覆盖Root级服务:由于ABCadminService是providedIn: 'root',需用overrideProvider强制替换为Mock实例,避免TestBed加载真实服务。

修改后的component.spec.ts代码:

import { of } from 'rxjs'; // 导入of操作符

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

  beforeEach(async () => {
    mockABCadminService = jasmine.createSpyObj(['getABC']);
    // 返回Observable类型的模拟数据
    mockABCadminService.getABC.and.returnValue(of('abc'));
    
    await TestBed.configureTestingModule({
      imports: [HttpClientModule],
      declarations: [GoComponent],
    })
    // 强制覆盖Root级的ABCadminService
    .overrideProvider(ABCadminService, { useValue: mockABCadminService })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(GoComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

备选方案:Mock依赖链中的ApiconfigurationService

如果上述方案仍不生效,可以直接MockABCadminService的依赖ApiconfigurationService,让真实的ABCadminService能正常实例化:

import { of } from 'rxjs';

describe('GoComponent', () => {
  let component: GoComponent;
  let fixture: ComponentFixture<GoComponent>;
  let mockABCadminService;
  let mockApiconfigService;

  beforeEach(async () => {
    mockApiconfigService = jasmine.createSpyObj(['getApiUrl']);
    mockApiconfigService.getApiUrl.and.returnValue('http://mock-url');
    
    mockABCadminService = jasmine.createSpyObj(['getABC']);
    mockABCadminService.getABC.and.returnValue(of('abc'));
    
    await TestBed.configureTestingModule({
      imports: [HttpClientModule],
      declarations: [GoComponent],
      providers: [
        { provide: ApiconfigurationService, useValue: mockApiconfigService },
        { provide: ABCadminService, useValue: mockABCadminService }
      ]
    }).compileComponents();
  });

  // ... 剩余测试代码不变
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:18:05