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未提供而报错。
修复步骤
- 确保Mock返回Observable:真实的
getABC方法返回Observable,组件中会调用subscribe,所以Mock必须返回Observable类型的值,而非字符串。 - 强制覆盖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
相关产品推荐
相关产品推荐

