我正在使用@ngrx/effects 4.1.1。我有一个返回空可观察值的效果,如下所示:
@Effect() showDialog$: Observable<Action> = this
.actions$
.ofType( ActionTypes.DIALOG_SHOW )
.map( ( action: DialogAction ) => action.payload )
.switchMap( payload => {
this.dialogsService.showDialog( payload.className );
return empty();
} );
我正在尝试按照这些指南编写一个单元测试,以测试该效果是否会产生空的可观察值。我有这个:
describe( 'DialogEffects', () => {
let effects: DialogEffects;
let actions: Observable<any>;
const mockDialogService = {
showDialog: sinon.stub()
};
beforeEach( () => {
TestBed.configureTestingModule( {
providers: [
DialogEffects, provideMockActions( () => actions ),
{
provide: DialogsService,
useValue: mockDialogService
}
]
} );
effects = TestBed.get( DialogEffects );
} );
describe( 'showDialog$', () => {
it( 'should return an empty observable', () => {
const dialogName = 'testDialog';
const action = showDialog( dialogName );
actions = hot( '--a-', { a: action } );
const expected = cold( '|' );
expect( effects.showDialog$ ).toBeObservable( expected );
} );
} );
} );
然而,Karma (v1.7.1) 抱怨:
预期 [ ] 等于 [ Object({frame: 0, notification:Notification({ kind: 'C', value: undefined, error: undefined, hasValue: false }) }) ]。如何测试效果是否返回
empty()
?我尝试使用
dispatch: false
修改效果元数据,但这没有效果。想法?
cold('|')
进行比较。
cold('|')
中的管道字符表示可观察流的完成。但是,您的效果不会完成。
empty()
observable 确实完成了,但是从
empty()
返回
switchMap
只是看到该 observable 合并到了effect observable 的流中——它并没有完成effect observable。相反,您应该将实际结果与
cold('')
进行比较 - 一个不发出任何值且未完成的可观察值。
@Effect({dispatch: false}) showDialog$ = this.actions$.pipe(
ofType( ActionTypes.DIALOG_SHOW ),
map( ( action: DialogAction ) => action.payload ),
tap( payload =>
this.dialogsService.showDialog( payload.className )
));
要测试它,你可以这样做
describe( 'showDialog$', () => {
it( 'should return an empty observable', () => {
const dialogName = 'testDialog';
const action = showDialog( dialogName );
actions = hot( '--a-', { a: action } );
expect(effects.showDialog$).toBeObservable(actions);
// here use mock framework to check the dialogService.showDialog is called
} );
} );
注意我使用 toBeObservable(actions) 的原因,这是因为由于 disptach false 这个效果不会产生任何东西,所以 actions 和以前一样,通过调用 toBeObservable(actions) 获得的好处是使测试同步,所以你可以之后检查您的服务是否是使用 jasmine 或 ts-mockito 等模拟框架调用的更新
我认为是时候更新一下了,ngrx 和 rxjs 都改变了我今天检查可观察量是否为空的方式:
describe( 'showDialog$', () => {
it( 'should return an empty observable', async () => {
const dialogName = 'testDialog';
actions = of( showDialog( dialogName ) );
const result = await firstValueFrom( effects.showDialog$.pipe(isEmpty()) );
expect( result ).toEqual( true );
} );
} );
我不再倾向于使用茉莉花弹珠,我通常只关心获得效果的最后值,而且茉莉花弹珠太过分了,因为我只在创建自定义运算符时才使用它们,
对于大多数常见情况, async wait 和 firstValueFrom 通常更好,对于空,只需添加 .pipe(isEmpty()) 就可以很好地解决问题
getEffectsMetadata 函数对其元数据进行断言:
expect(getEffectsMetadata(effects).deleteSnapshotSuccess$?.dispatch).toBe(false)
以上已经用ngrx 9.0.0测试过。由于无论
dispatch
如何,所有可观察量都会发出,因此像
expect(effects.effect$).toBeObservable(cold(''))
这样的检查不会产生预期的结果。