我有一个门面类,它在窗帘后面使用 NgRx。当我在我的应用程序中使用它时,外观本身正在工作,但是通过集成测试它不起作用(更好的说法是:测试不起作用)。我正在使用 Nx(不认为这很重要)和 Jest。
注意:对于集成测试,我的意思是我不想模拟 NgRx 部分,我也想测试 NgRx 逻辑。只有数据服务被模拟。
外观类非常简单。这是它的摘录:
@Injectable({
providedIn: 'root'
})
export class ProfileFacade {
public isProfileLoaded$ = this.store.select(Selectors.isProfileLoaded);
public constructor(private store: Store<fromProfile.PartialState>) {
/* */
}
public loadProfile(): void {
this.dispatch(Actions.loadProfile());
}
private dispatch(action: Action): void {
this.store.dispatch(action);
}
}
已分配的loadProfile操作会触发一个效果,该效果会返回包含通过 ProfileService 获取的数据的 ProfileLoadSucceeded 操作。然后,reducer 捕获此操作,将配置文件数据放入存储中,并将 isProfileLoaded 属性设置为 true。
这是我的集成测试的设置:
describe('ProfileFacade integration', () => {
let facade: ProfileFacade;
let store: Store<fromProfile.PartialState>;
let profileServiceSpy: SpyObject<ProfileService>;
beforeEach(() => {
@NgModule({
imports: [
StoreModule.forFeature(fromProfile.PROFILE_FEATURE_KEY, fromProfile.reducer),
EffectsModule.forFeature([ProfileEffects])
],
providers: [
ProfileFacade,
mockProvider(ProfileService),
]
})
class CustomFeatureModule {}
@NgModule({
imports: [NxModule.forRoot(), StoreModule.forRoot({}), EffectsModule.forRoot([]), CustomFeatureModule]
})
class RootModule {}
TestBed.configureTestingModule({ imports: [RootModule] });
store = TestBed.inject(Store);
facade = TestBed.inject(ProfileFacade);
profileServiceSpy = TestBed.inject(ProfileService) as SpyObject<ProfileService>;
});
...
});
以下是我在集成测试中尝试过的许多事情的选择:
使用 expect(...).toBeObservable(...)
it(`should set isProfileLoaded to true`, () => { profileServiceSpy.get.and.returnValue(hot('^x|', { x: profile })); // I've tried several variations of hot and cold facade.loadProfile(); const expected = cold('--b', { b: true }); expect(facade.isProfileLoaded$).toBeObservable(expected); });
使用 toPromise() 和 then()
it(`should set isProfileLoaded to true`, () => { // same 2 lines as in 1) return facade.isProfileLoaded$.toPromise().then(result => expect(result).toBe(true)); });
与 expect(...toPromise()).resolves()
it(`should set isProfileLoaded to true`, () => { // same 2 lines as in 1) return expect(facade.isProfileLoaded$.toPromise()).resolves.toBe(true); });
使用 subscribe 和 done()
it(`should set isProfileLoaded to true`, done => { // same 2 lines as in 1) facade.isProfileLoaded$.subscribe(result => { expect(result).toBe(true); done(); }); });
我只是展示了 isProfileLoaded 的测试,但我对数据本身的测试也有同样的问题。结果值始终为 false 或 null:外观的选择器结果似乎没有反映商店的内容。
不过,这家商店本身似乎运作良好。通过在不同的地方添加 console.log 语句,我可以看到来自模拟服务的数据正在正常流动。它存在于效果、reducer 和结果状态中。
我想我遗漏了一些明显的东西,但是什么?我还没有找到使用这种技术组合执行这种集成测试的示例。