Angular组件单元测试报错:No provider for NgControl
解决Angular测试中"No Provider for NgControl"的问题
你在测试带复杂表单的Angular组件时遇到的这个报错,是测试环境下很常见的依赖缺失问题——毕竟TestBed不会自动加载组件运行时所需的所有模块和服务,得我们手动补全。下面一步步帮你解决:
错误根源拆解
你的组件模板里用到了formGroup、formControlName这类响应式表单指令,还有Angular Material的表单组件以及Translate管道,但测试模块里没有提供这些依赖的提供者,所以才会抛出No Provider for NgControl和ControlContainer的错误。
具体修复步骤
1. 导入响应式表单核心模块
既然用了formGroup和formControlName,首先要在测试模块里导入ReactiveFormsModule,它会提供所有响应式表单指令的依赖:
import { ReactiveFormsModule } from '@angular/forms'; TestBed.configureTestingModule({ declarations: [ConfiguratorComponent, CustomerComponent], // 必须声明嵌套的CustomerComponent imports: [ReactiveFormsModule] });
2. 添加Angular Material表单模块
模板里的mat-form-field和matInput属于Angular Material组件,得导入对应的模块才能让测试环境识别:
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; // 在TestBed的imports数组中补充 imports: [ ReactiveFormsModule, MatFormFieldModule, MatInputModule ]
3. 处理Translate管道依赖
模板里的{{'customer.lastname' | translate}}用到了Translate管道,你可以直接导入TranslateModule的基础版本,或者模拟TranslateService:
import { TranslateModule } from '@ngx-translate/core'; // 在imports里添加 TranslateModule.forRoot()
4. 手动提供NgControl(兜底方案)
如果做完上面几步还是报错,可以手动提供NgControl的模拟实现,强制解决依赖问题:
import { NgControl } from '@angular/forms'; import { FormControl } from '@angular/forms'; // 在providers数组中添加 providers: [ { provide: NgControl, useValue: { control: new FormControl(), valueAccessor: {} } } ]
完整TestBed配置示例
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ConfiguratorComponent } from './configurator.component'; import { CustomerComponent } from './customer.component'; import { ReactiveFormsModule, FormGroup, FormControl } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { TranslateModule } from '@ngx-translate/core'; import { NgControl } from '@angular/forms'; describe('ConfiguratorComponent', () => { let component: ConfiguratorComponent; let fixture: ComponentFixture<ConfiguratorComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ConfiguratorComponent, CustomerComponent], imports: [ ReactiveFormsModule, MatFormFieldModule, MatInputModule, TranslateModule.forRoot() ], providers: [ { provide: NgControl, useValue: { control: new FormControl(), valueAccessor: {} } } ] }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(ConfiguratorComponent); component = fixture.componentInstance; // 别忘了初始化组件里的formGroup,否则模板绑定会报错 component.options = new FormGroup({ lastname: new FormControl(''), email: new FormControl(''), firstname: new FormControl('') }); fixture.detectChanges(); }); it('has a configurator', () => { expect(component).toBeTruthy(); }); });
最后提醒一句:组件里的options FormGroup一定要在测试前初始化好,不然模板里的[formGroup]="options"也会触发新的错误。
内容的提问来源于stack exchange,提问作者Marco Papula
相关产品推荐
相关产品推荐

