使用TestBed覆盖NgRx Store测试配置遇阻求助
问题原因
你用TestBed.overrideModule尝试覆盖Store配置的思路存在核心问题:StoreModule.forRoot()和StoreModule.forFeature()是工厂函数,每次调用都会生成全新的ModuleWithProviders实例。你在remove选项里指定的StoreModule.forRoot({})和全局配置里的StoreModule.forRoot({ products: productsReducer, ... })根本不是同一个对象,TestBed找不到要移除的模块,自然覆盖操作完全无效。
解决方案
放弃overrideModule,直接在局部describe中调用TestBed.configureTestingModule()重新定义Store配置。TestBed的配置会从父级describe继承,你只需要覆盖imports中Store相关的配置即可。另外,为了避免全局Store状态污染局部测试,记得在测试前重置Store状态。
代码示例
全局配置保持不变,局部测试的beforeEach修改如下:
beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ // 重新配置全局Store,可按需修改reducer StoreModule.forRoot({ products: productsReducer, // 保留全局其他reducer,或按需调整 ... }), // 重新配置目标feature,替换需要修改的reducer StoreModule.forFeature(smartRecoFeatureKey, { ...fromSmartReco.reducers, recommendationErrorType: ( state: ProductRecommendationErrorTypes = ProductRecommendationErrorTypes.TECHNICAL, type: Action ) => state // 这里实现你的自定义reducer逻辑,示例直接返回初始状态 }), // 若父级有其他必要导入(如CommonModule、其他组件依赖模块),需一并包含 ... ] }).compileComponents(); // 重置Store状态,避免全局状态污染当前测试 const store = TestBed.inject(Store); store.dispatch({ type: '@ngrx/store/reset' }); // 也可dispatch自定义的重置动作,根据你的reducer实现调整 });
补充说明
如果只需要修改某个feature的配置,不需要改动全局forRoot的内容,也可以只重新导入该StoreModule.forFeature——TestBed会合并配置,但要确保feature key唯一,避免冲突。如果担心重复导入的问题,也可以先调用TestBed.resetTestingModule()清空之前的配置,再重新初始化,但这样会丢失父级的所有配置,需要手动重新添加所有依赖模块。
内容的提问来源于stack exchange,提问作者balteo

