Angular Material CDK数据表结合NgRx Store单元测试参数解析错误求助
错误原因分析
这个错误提示Can't resolve all parameters for ObservableDataSource: ([object Object], ?)说明你的ObservableDataSource构造函数有两个参数,Angular的依赖注入系统能解析第一个参数,但第二个参数找不到对应的提供者。通常是因为测试模块中没有配置好该类所需的全部依赖,或者构造函数的参数类型没有被正确识别(比如使用了非类类型的参数,却没添加@Inject()装饰器)。
具体解决步骤
1. 先明确ObservableDataSource的构造函数依赖
首先确认你的ObservableDataSource构造函数的参数结构,比如它可能是这样的:
import { DataSource } from '@angular/cdk/collections'; import { Store } from '@ngrx/store'; import { SomeService } from './some.service'; import { Observable } from 'rxjs'; export class ObservableDataSource<T> extends DataSource<T> { constructor( private store: Store<YourAppState>, private dataService: SomeService // 第二个待解析的依赖 ) { super(); } connect(): Observable<T[]> { // 结合ngrx store的数据选择逻辑 return this.store.select(selectYourTargetData); } disconnect() {} }
2. 在测试模块中配置所有依赖的提供者
在组件的单元测试文件里,你需要在TestBed.configureTestingModule中为ObservableDataSource的所有构造函数参数提供mock实例或对应依赖:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { YourComponent } from './your.component'; import { ObservableDataSource } from './observable-data-source'; import { Store } from '@ngrx/store'; import { provideMockStore } from '@ngrx/store/testing'; import { SomeService } from './some.service'; describe('YourComponent', () => { let component: YourComponent; let fixture: ComponentFixture<YourComponent>; let mockStore: any; let mockSomeService: jasmine.SpyObj<SomeService>; beforeEach(async () => { // 创建mock服务,模拟原服务的方法 mockSomeService = jasmine.createSpyObj('SomeService', ['fetchExtraData']); await TestBed.configureTestingModule({ declarations: [YourComponent], providers: [ // 注册ObservableDataSource,让DI系统能创建它的实例 ObservableDataSource, // 为ngrx store提供mock实例,传入初始状态 provideMockStore({ initialState: { yourFeature: {} } }), // 提供mock的SomeService替代真实服务 { provide: SomeService, useValue: mockSomeService } ] }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(YourComponent); component = fixture.componentInstance; mockStore = TestBed.inject(Store); fixture.detectChanges(); }); it('should create the component', () => { expect(component).toBeTruthy(); }); });
3. 特殊情况:处理非类类型的构造参数
如果你的ObservableDataSource构造函数中有非类类型的参数(比如配置对象、字符串常量),需要用@Inject()装饰器标记它,同时在测试中提供对应的注入token:
比如构造函数是这样的:
import { Inject, InjectionToken } from '@angular/core'; // 定义注入token export const DATA_TABLE_CONFIG = new InjectionToken<{ pageSize: number }>('data.table.config'); export class ObservableDataSource<T> extends DataSource<T> { constructor( private store: Store<YourAppState>, @Inject(DATA_TABLE_CONFIG) private config: { pageSize: number } ) { super(); } }
那测试中需要补充这个token的提供者:
providers: [ ObservableDataSource, provideMockStore({ initialState: {} }), { provide: DATA_TABLE_CONFIG, useValue: { pageSize: 20 } } ]
4. 确认组件中正确注入ObservableDataSource
还要确保你的组件是通过依赖注入获取ObservableDataSource,而不是手动new实例:
@Component({ selector: 'app-your-component', templateUrl: './your.component.html' }) export class YourComponent { dataSource: ObservableDataSource<YourDataType>; // 通过构造函数注入,而非手动new constructor(dataSource: ObservableDataSource<YourDataType>) { this.dataSource = dataSource; } }
如果是手动new的,那测试中需要自己传入所有构造参数,而非依赖Angular的DI系统。
总结
核心思路就是确保ObservableDataSource的所有构造函数参数,在测试模块的providers数组中都有对应的提供者——不管是mock服务、ngrx的mock store,还是自定义的注入token,都要配置到位,这样Angular的DI系统才能正确解析所有参数,解决这个错误。
内容的提问来源于stack exchange,提问作者Charlie-Greenman

