如何使用茉莉花大理石在rxjs管道中测试timeout() [英] How to test timeout() in a rxjs pipe with jasmine-marbles
问题描述
我写了一个管道来过滤可观察的输入.在管道中,我使用timeout()运算符指定一个超时,以在源未及时发出期望值的情况下中止等待.
我想用茉莉花大理石测试超时情况,但无法正常工作.
我相信 expect(source).toBeObservable()
在源发出之前进行评估.
I have written a pipe that filters an input observable. In the pipe I specify a timeout with the timeout() operator to abort waiting if the expected value is not emitted by the source in time.
I want to test the timeout case with jasmine-marbles, but I can't get it to work.
I believe that expect(source).toBeObservable()
evaluates before the source emits.
请参见 Stackblitz
要测试的管道:
source = cold('a', { a: { id: 'a' } }).pipe(
timeout(500),
filter((a) => false),
catchError((err) => {
return of({ timeout: true })
}),
take(1)
);
使用toPromise()进行测试按预期进行:
Testing with toPromise() works as expected:
expect(await source.toPromise()).toEqual({ timeout: true });
用茉莉花大理石进行测试
Testing with jasmine-marbles
const expected = cold('500ms (a|)', { a: { timeout: true } });
expect(source).toBeObservable(expected);
失败,并显示错误
Expected $.length = 0 to equal 2.
Expected $[0] = undefined to equal Object({ frame: 500, notification: Notification({ kind: 'N', value: Object({ timeout: true }), error: undefined, hasValue: true }) }).
Expected $[1] = undefined to equal Object({ frame: 500, notification: Notification({ kind: 'C', value: undefined, error: undefined, hasValue: false }) }).
推荐答案
Support for time progression was recently added (see jasmine-marbles PR #38) to jasmine-marbles 0.5.0. Additional test specs were added to the package that demonstrate one of a couple of possible ways to accomplish what you want. Here are some options I was able to throw together using your Stackblitz sample.
在测试方法之外(例如,在beforeEach
中)初始化可观察到的源时,必须显式初始化并将测试调度程序传递给timeout
,以使expect().toBeObservable()
正常工作.但是,请注意,此更改将中断应与toPromise一起使用"测试. (我不知道为什么,但是toPromise()
似乎不适用于这种方法.)
When you initialize the source observable outside the test method (e.g. in beforeEach
), you must explicitly initialize and pass the test scheduler to timeout
to get expect().toBeObservable()
working. However, take note that this change will break the "should work with toPromise" test. (I don't know why, but toPromise()
doesn't appear to work with this approach.)
describe('Marble testing with timeout', () => {
let source;
beforeEach(() => {
// You must explicitly init the test scheduler in `beforeEach`.
initTestScheduler()
source = cold('a', { a: { id: 'a' } }).pipe(
// You must explicitly pass the test scheduler.
timeout(500, getTestScheduler()),
filter((a) => false),
catchError(err => {
return of({ timeout: true })
}),
take(1)
);
});
it('should work with toBeObservable', () => {
const expected = cold('500ms (a|)', { a: { timeout: true } });
expect(source).toBeObservable(expected);
});
});
选项2
您可以进行一些重构,并初始化测试方法(beforeEach
中的不是)中可观察到的源.您无需显式初始化测试计划程序(茉莉花大理石将在测试方法运行之前为您完成此工作),但是您仍然必须将其传递给timeout
.请注意createSource
函数如何与测试计划程序或默认计划程序一起使用(如果scheduler
参数保留为undefined
).此选项适用于应与toPromise一起使用"测试和应与toBeObservable"一起使用.
Option 2
You can refactor things slightly and initialize the source observable inside the test method (not in beforeEach
). You don't need to explicitly initializes the test scheduler (jasmine-marbles will do it for you before the test method runs), but you still have to pass it to timeout
. Note how the createSource
function can be used with the test scheduler or the default scheduler (if the scheduler
argument is left undefined
). This options works with both the "should work with toPromise" test and the "should work with toBeObservable" test.
describe('Marble testing with timeout', () => {
const createSource = (scheduler = undefined) => {
return cold('a', { a: { id: 'a' } }).pipe(
// You must explicitly pass the test scheduler (or undefined to use the default scheduler).
timeout(500, scheduler),
filter((a) => false),
catchError(err => {
return of({ timeout: true })
}),
take(1)
);
};
it('should work with toPromise', async () => {
const source = createSource();
expect(await source.toPromise()).toEqual({ timeout: true });
});
it('should work with toBeObservable', () => {
const source = createSource(getTestScheduler());
const expected = cold('500ms (a|)', { a: { timeout: true } });
expect(source).toBeObservable(expected);
});
});
选项3
最后,如果您明确使用测试计划程序的run
方法,则可以跳过将测试计划程序传递给timeout
的步骤,但是必须使用expectObservable
(而不是expect().toBeObservable()
.它可以正常工作,但是茉莉花香将报告警告规格没有预期".
Option 3
Finally, you can skip passing the test scheduler to timeout
if you explicitly use the test scheduler's run
method, but you must use expectObservable
(as opposed to expect().toBeObservable()
. It works just fine, but Jasmine will report the warning "SPEC HAS NO EXPECTATIONS".
describe('Marble testing with timeout', () => {
let source;
beforeEach(() => {
source = cold('a', { a: { id: 'a' } }).pipe(
timeout(500),
filter((a) => false),
catchError(err => {
return of({ timeout: true })
}),
take(1)
);
});
it('should work with scheduler and expectObservable', () => {
const scheduler = getTestScheduler();
scheduler.run(({ expectObservable }) => {
expectObservable(source).toBe('500ms (0|)', [{ timeout: true }]);
});
});
});
这篇关于如何使用茉莉花大理石在rxjs管道中测试timeout()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!