@ngrx/effects:测试效果返回空()

问题描述 投票:0回答:3

我正在使用@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
 修改效果元数据,但这没有效果。

想法?

angular unit-testing karma-jasmine ngrx-effects
3个回答
12
投票
问题在于您正在将实际结果与

cold('|')

进行比较。

cold('|')

中的管道字符表示可观察流的完成。但是,您的效果不会完成。 
empty()
 observable 确实完成了,但是从 
empty()
 返回 
switchMap
 只是看到该 observable 合并到了effect observable 的流中——它并没有完成effect observable。

相反,您应该将实际结果与

cold('')

 进行比较 - 一个不发出任何值且未完成的可观察值。


6
投票
最好的方法是在效果中使用dispatch false并更改tap的swicthMap

@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()) 就可以很好地解决问题


2
投票
要测试效果是否未调度,您可以使用

getEffectsMetadata 函数对其元数据进行断言:

expect(getEffectsMetadata(effects).deleteSnapshotSuccess$?.dispatch).toBe(false)

以上已经用ngrx 9.0.0测试过。由于无论

dispatch

如何,所有可观察量都会发出,因此像
expect(effects.effect$).toBeObservable(cold(''))
这样的检查不会产生预期的结果。

© www.soinside.com 2019 - 2024. All rights reserved.