我正在使用NGRX,并使用“效果”发送HTTP请求。如果用户发送另一个请求,则任何先前的请求都应被取消。当我手动测试时,它工作正常,但我希望能够对此进行单元测试。为了测试这一点,我模拟了发送HTTP请求并在一定延迟后发送响应的服务。然后,我有一个Marble hot observable触发了4个请求。我希望我的效果只会触发一次。但是,它根本不会被触发。
单元测试:
it('should only do one request at a time', fakeAsync(() => {
// Arrange
const data = createTestData();
const dataServiceSpy = TestBed.get(DataService);
dataServiceSpy.getData = jest.fn(
(query: DataQuery) => {
const waitTime = 1000 * + query.index;
return of(assets).pipe(delay(waitTime));
}
);
// Act
actions = hot('-abcd-|', {
a: new SearchData({ index: '6' }),
b: new SearchData({ index: '5' }),
c: new SearchData({ index: '4' }),
d: new SearchData({ index: '1' })
});
tick(10000);
// Assert
expect(effects.loadData$).toBeObservable(
hot('-a-|', { a: new SearchDataComplete(assets) })
);
}));
因此,我要发送4个搜索请求;第一个应在6秒后返回数据,第二个应在5秒后返回数据,依此类推。 但是,我的单元测试失败了,因为loadData $是空的可观察到的东西,但它预期只有一项。
如果我删除了间谍中的延迟,则它将按预期工作,并且loadData $包含4个结果。
My Effect正在使用NX DataPersistence,如果您提供id函数,它将负责取消操作;如果有新的动作具有相同的ID,它将取消初始请求。类似于使用this.actions $ .pipe(switchMap(...))
@Effect()
loadData$ = this.dataPersistence.fetch(ActionTypes.SearchData, {
id: (action, state) => {
return action.type
},
run: (action, state) => {
return this.dataService
.searchData(action.payload)
.pipe(
map(data => new SearchDataComplete(data))
);
},
答案 0 :(得分:1)
所以我对此进行了一些研究。我有两个想法:
delay
进行测试时存在一个实际问题在您的测试中,tick
会在订阅该效果之前触发(当您在其下方调用expect
时)。
一种解决方法如下:
describe('loadTest$', () => {
it('should only do one request at a time', () => {
// create a synchronous scheduler (VirtualTime)
const scheduler = new VirtualTimeScheduler();
// Arrange
const data = createTestData();
const dataServiceSpy = TestBed.get(DataService);
TestBed.configureTestingModule({
imports: [NxModule.forRoot(), StoreModule.forRoot({})],
providers: [
TestEffects,
provideMockActions(() => actions),
{
provide: DataService,
useValue: {
searchData: jest.fn(
(query: DataQuery) => {
const waitTime = 1000 * + query.index;
return of(assets).pipe(delay(waitTime, scheduler));
}
)
}
}
]
});
actions = of(
new SearchData({ index: '6' }),
new SearchData({ index: '5' }),
new SearchData({ index: '4' }),
new SearchData({ index: '1' })
);
const res = [];
effects.loadData$.subscribe(val => res.push(val));
scheduler.flush(); // we flush the observable here
expect(res).toEqual([{ a: new SearchDataComplete(assets) }]);
});
});
我们可以使用同步调度程序并手动刷新它。通常,我们不需要执行任何操作。仅仅是因为我们需要delay
(其他需要调度程序的运营商(例如debounceTime
也会发生这种情况)。
希望这会有所帮助。我认为您的测试不需要测试基础库的功能(在那时,它可能不是严格的单元测试,而更多的是集成测试)。