我有一个管道可以帮助返回一个可观察对象的状态。
import {Pipe, PipeTransform} from '@angular/core';
import {Observable, of} from 'rxjs';
import {catchError, map, startWith} from 'rxjs/operators';
/** Specifies the status of an Observable. */
export interface ObservableStatus<T> {
loading?: boolean;
value?: T;
error?: boolean;
}
/** Returns the status {@code ObservableStatus} of a given Observable. */
@Pipe({name: 'getObserverStatus'})
export class ObservableStatusPipe implements PipeTransform {
transform<T = Item>(observer: Observable<T>):
Observable<ObservableStatus<T>> {
return observer.pipe(
map((value: T) => {
return {
loading: false,
error: false,
value,
};
}),
startWith({loading: true}),
catchError(error => of({loading: false, error: true})));
}
}
我想用Jasmine为这个功能编写单元测试。我试着用fakeAsync, delay, tick, flush, discardPeriodicTasks
,但是好像不起作用。
我尝试过不同的方法:
- 方式一
describe('loading test', () => {
const loadingPipe = new ObservableStatusPipe();
it('returns state of an observable', fakeAsync(() => {
const input: Observable<Item> = of({name: 'Item'}).pipe(delay(1000));
const result: Observable<ObservableStatus<Item>> = loadingPipe.transform(input);
result.subscribe(val => {
expect(val.loading).toEqual(true);
expect(val.value).toBeUndefined();
});
tick(2000);
result.subscribe(val => {
expect(val.loading).toEqual(false);
expect(val.value!.name).toEqual('Item');
});
}));
});
上述测试用例未通过,故障如下:
Error: Expected true to equal false. (at expect(val.loading).toEqual(false))
Error: 1 periodic timer(s) still in the queue.
- 方法2:从网上,我看到我们可以使用flush来刷新任何挂起的任务。
describe('loading test', () => {
const loadingPipe = new ObservableStatusPipe();
it('returns state of an observable', fakeAsync(() => {
const input: Observable<Item> = of({name: 'Item'}).pipe(delay(1000));
const result: Observable<ObservableStatus<Item>> = loadingPipe.transform(input);
result.subscribe(val => {
expect(val.loading).toEqual(true);
expect(val.value).toBeUndefined();
});
tick(2000);
result.subscribe(val => {
expect(val.loading).toEqual(false);
expect(val.value!.name).toEqual('Item');
});
flush(); // <----- here.
}));
});
这有助于解决Error: 1 periodic timer(s) still in the queue.
问题。但是,测试用例仍然失败,原因如下:
Error: Expected true to equal false.
TypeError: Cannot read properties of undefined (reading 'name')
所有这一切是否意味着tick
在某种程度上没有模拟input
上的时间?
- 我在
input
上直接测试了相同的模拟:
describe('loading test', () => {
const loadingPipe = new ObservableStatusPipe();
it('returns state of an observable', fakeAsync(() => {
const input: Observable<Item> = of({name: 'Item'}).pipe(delay(1000));
input.subscribe(val => {
expect(val.name).toBeUndefined();
});
tick(2000);
input.subscribe(val => {
expect(val.name).toEqual('Item');
});
discardPeriodicTasks(); <--- Using flush() here is causing 'Error: 2 periodic timer(s) still in the queue' error.
}));
});
上面的测试用例通过了。但是我仍然不明白为什么flush()在这里不起作用。
- 方法3:尝试使用上面的discardPeriodicTasks技巧来解决我最初的问题。
describe('loading test', () => {
const loadingPipe = new ObservableStatusPipe();
it('returns state of an observable', fakeAsync(() => {
const input: Observable<Item> = of({name: 'Item'}).pipe(delay(1000));
const result: Observable<ObservableStatus<Item>> = loadingPipe.transform(input);
result.subscribe(val => {
expect(val.loading).toEqual(true);
expect(val.value).toBeUndefined();
});
tick(2000);
result.subscribe(val => {
expect(val.loading).toEqual(false);
expect(val.value!.name).toEqual('Item');
});
discardPeriodicTasks();
}));
});
这仍然会失败,并显示相同的错误:
Error: Expected true to equal false. (at expect(val.loading).toEqual(false))
Error: 1 periodic timer(s) still in the queue.
有人能解释一下这里发生了什么吗,以及如何解决这个问题?
- 顺便说一句,我不想使用
debounceTime
,setTimeOut
来解决这个问题。因为它们看起来不像是模拟时间,而是实际上等待和延迟时间,即使用debounceTime(1000)实际上会等待1秒。我不想在我的情况下(我想模拟时间)。**
- 顺便说一句,我不想使用
- 订阅可观察对象时使用
delay
运算符有效(不使用tick
)。
describe('loading test', () => {
const loadingPipe = new ObservableStatusPipe();
it('returns state of an observable', fakeAsync(() => {
const input: Observable<Item> = of({name: 'Item'}).pipe(delay(1000));
const result: Observable<ObservableStatus<Item>> = loadingPipe.transform(input);
result.subscribe(val => {
expect(val.loading).toEqual(true);
expect(val.value).toBeUndefined();
});
result.pipe(delay(2000)).subscribe(val => {
expect(val.loading).toEqual(false);
expect(val.value!.name).toEqual('Item');
});
discardPeriodicTasks();
}));
});
这实际上是延迟/等待1000或2000ms,还是使用fakeAsync以某种方式让延迟来模拟时间?
谢谢!
1条答案
按热度按时间l7wslrjt1#
我认为你的方式1是好的,但你可能会面临迟订阅和多订阅的情况。试试这个: