我正在尝试在角度应用程序中对 ngrx 效果进行单元测试,该效果使用计时器引入一些轮询逻辑,并根据某些选择器的值映射到一些操作。
我的代码是这样的:
@Injectable()
export class YourEffects {
timerEffect$ = createEffect(() =>
this.actions$.pipe(
ofType(fromActions.startTimerAction),
switchMap(() =>
timer(0, 1000).pipe(
withLatestFrom(this.store.select(selectCondition)),
map(() => {
if (condition) {
return fromActions.timerTickAction1()
}
return fromActions.timerTickAction2()
})
)
)
)
);
constructor(private actions$: Actions) {}
}
我成功地用
fakeAsync
使用这种方法对此进行了单元测试,但在使用 Jasmine Marbels 时遇到了麻烦
尝试像这样和茉莉一起转移时间
it('should emit timerTickAction every second', () => {
// Arrange
store.overrideSelector(selectCondition, someFalsyValue);
const startAction = fromActions.startTimerAction();
const tickAction = fromActions.timerTickAction2();
// Act
actions = hot('-a', { a: startAction });
// Use jasmine.clock().install() to control the passage of time
jasmine.clock().install();
// Simulate the passage of time and test the effect
jasmine.clock().tick(1000); // 1 second
const expected = cold('-b', { b: tickAction });
// Assert
expect(effects.timerEffect$).toBeObservable(expected);
// Clean up the clock
jasmine.clock().uninstall();
});
如果有人能建议使用弹珠进行测试的方法,我将非常感激。谢谢!
从我自己的一些测试中,我发现使用
jasmine-marbles
我可以使用 timer
或 interval
来测试可观察量,前提是它们在 TestScheduler.run()
回调中运行。我无法找到为什么会这样的彻底解释。
另一点是,在编写弹珠测试时,您必须在某个时刻完成您的可观察量。有时就像
timer
或 interval
的情况一样,如果在源代码或测试设置中没有传递完成机制,则可观察对象永远不会完成,并且测试将因此无法工作。这在 rxjs
仓库的本期中提到:https://github.com/ReactiveX/rxjs/issues/3957
另请查看这篇关于大理石测试的文档:https://rxjs.dev/guide/testing/marble-testing#time-progression-syntax。 这将解释为什么在我们的弹珠中我们使用
999ms
而不是 1s
。
考虑到所有这些,这就是我测试您的效果代码的方式:
it('should emit twice, on start and after 1s', () => {
// given
store.overrideSelector(selectCondition, someFalsyValue);
const startAction = fromActions.startTimerAction();
const tickAction = fromActions.timerTickAction2();
const scheduler = getTestScheduler();
scheduler.run(() => {
// when
actions$ = hot('a', {
a: startAction
});
// then
const expected = cold('a 999ms (a |)', {
a: tickAction
});
expect(effects.timerEffect$.pipe(take(2))).toBeObservable(expected);
});
});
getTestScheduler()
是从 jasmine-marble
导入的,hot
和 cold
相同。
如果使用
take(3)
而不是 take(2)
,你的输出大理石应该看起来像这样 a 999ms a 999ms (a |)
。
希望这有帮助。