如何测试angular数据缓存?
How to test angular data caching?
我有一个与我们的 API 通信的 angular 服务。可以在本地缓存对相同数据的某些请求,以帮助感觉更快一些。
这里基本上是在执行一些缓存的服务方法中发生的事情:
private thingCache: IThing[] = [];
getThing$(thingId: string): Observable<IThing> {
const cachedThing = this.thingCache.find(( => l.id === thingId);
if (cachedThing) {
return of(cachedThing);
}
const fetchedThing$ = this.http.get<IThing>(`http://our-api/thing/${thingId}`)
.pipe(tap((thing: IThing) => {
//add any retrieved login to the cache
//we already checked above that it's not in the cache, so we know we are adding a new one here
this.thingCache.push(thing);
}));
return fetchedThing$;
}
所以在测试中,我需要测试第一个调用是否来自实际的 HTTP GET 请求,而之后的任何调用都不是。执行此操作的最佳方法是什么?
这是我测试第一个调用的方法,它确实有效
describe('Service: api', () => {
let service: ApiService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule ],
providers: [ ApiService ]
});
service = TestBed.get(ApiService);
httpMock = TestBed.get(HttpTestingController);
});
afterEach(() => {
httpMock.verify();
});
it('should GET a thing when calling getThing$() with a thing ID', () => {
service.getThing$('1234-5678-9012').subscribe((value: IThing) => {
expect(value).toEqual({
id: '148e265b-b284-84b7-b8b3-441854f15783', otherData: 'foo'
} as IThing);
}, () => {
fail('The subscription to getThing$() has errored out!');
});
const req = httpMock.expectOne('http://our-api/thing/1234-5678-9012');
expect(req.request.method).toEqual('GET');
req.flush({
id: '148e265b-b284-84b7-b8b3-441854f15783', otherData: 'foo'
} as IThing);
});
});
好吧,事实证明这比我想象的要简单一些。取消订阅,然后重新订阅。
it('should return a thing from the API on the first call, and from cache on the 2nd call for the same data', () => {
const sub1 = service.getThing$('148e265b-b284-84b7-b8b3-441854f15783').subscribe((value: IThing) => {
expect(value).toEqual({
id: '148e265b-b284-84b7-b8b3-441854f15783', otherData: 'foo'
} as IThing);
}, () => {
fail('The subscription to getThing$() has errored out!');
});
const req = httpMock.expectOne('http://our-api/thing/148e265b-b284-84b7-b8b3-441854f15783');
expect(req.request.method).toEqual('GET');
req.flush({
id: '148e265b-b284-84b7-b8b3-441854f15783', otherData: 'foo'
} as IThing);
//----------------------------------------------------------------------
//Ensure a 2nd call for the same ID does not make an HTTP call
sub1.unsubscribe();
const sub2 = service.getThing$('148e265b-b284-84b7-b8b3-441854f15783').subscribe((value: IThing) => {
expect(value).toEqual({
id: '148e265b-b284-84b7-b8b3-441854f15783', otherData: 'foo'
} as IThing);
}, () => {
fail('The subscription to getThing$() has errored out!');
});
httpMock.expectNone('http://our-api/thing/148e265b-b284-84b7-b8b3-441854f15783');
//----------------------------------------------------------------------
//Ensure a 3rd call for a DIFFERENT ID still makes an HTTP request for the new un-cached data
sub2.unsubscribe();
service.getThing$('111e2222-bbbb-8888-cccc-444455555777').subscribe((value: IThing) => {
expect(value).toEqual({
id: '111e2222-bbbb-8888-cccc-444455555777', otherData: 'bar'
} as IThing);
}, () => {
fail('The subscription to getThing$() has errored out!');
});
const req3 = httpMock.expectOne('http://our-api/thing/111e2222-bbbb-8888-cccc-444455555777');
expect(req3.request.method).toEqual('GET');
req3.flush({
id: '111e2222-bbbb-8888-cccc-444455555777', otherData: 'bar'
} as IThing);
});
我有一个与我们的 API 通信的 angular 服务。可以在本地缓存对相同数据的某些请求,以帮助感觉更快一些。
这里基本上是在执行一些缓存的服务方法中发生的事情:
private thingCache: IThing[] = [];
getThing$(thingId: string): Observable<IThing> {
const cachedThing = this.thingCache.find(( => l.id === thingId);
if (cachedThing) {
return of(cachedThing);
}
const fetchedThing$ = this.http.get<IThing>(`http://our-api/thing/${thingId}`)
.pipe(tap((thing: IThing) => {
//add any retrieved login to the cache
//we already checked above that it's not in the cache, so we know we are adding a new one here
this.thingCache.push(thing);
}));
return fetchedThing$;
}
所以在测试中,我需要测试第一个调用是否来自实际的 HTTP GET 请求,而之后的任何调用都不是。执行此操作的最佳方法是什么?
这是我测试第一个调用的方法,它确实有效
describe('Service: api', () => {
let service: ApiService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule ],
providers: [ ApiService ]
});
service = TestBed.get(ApiService);
httpMock = TestBed.get(HttpTestingController);
});
afterEach(() => {
httpMock.verify();
});
it('should GET a thing when calling getThing$() with a thing ID', () => {
service.getThing$('1234-5678-9012').subscribe((value: IThing) => {
expect(value).toEqual({
id: '148e265b-b284-84b7-b8b3-441854f15783', otherData: 'foo'
} as IThing);
}, () => {
fail('The subscription to getThing$() has errored out!');
});
const req = httpMock.expectOne('http://our-api/thing/1234-5678-9012');
expect(req.request.method).toEqual('GET');
req.flush({
id: '148e265b-b284-84b7-b8b3-441854f15783', otherData: 'foo'
} as IThing);
});
});
好吧,事实证明这比我想象的要简单一些。取消订阅,然后重新订阅。
it('should return a thing from the API on the first call, and from cache on the 2nd call for the same data', () => {
const sub1 = service.getThing$('148e265b-b284-84b7-b8b3-441854f15783').subscribe((value: IThing) => {
expect(value).toEqual({
id: '148e265b-b284-84b7-b8b3-441854f15783', otherData: 'foo'
} as IThing);
}, () => {
fail('The subscription to getThing$() has errored out!');
});
const req = httpMock.expectOne('http://our-api/thing/148e265b-b284-84b7-b8b3-441854f15783');
expect(req.request.method).toEqual('GET');
req.flush({
id: '148e265b-b284-84b7-b8b3-441854f15783', otherData: 'foo'
} as IThing);
//----------------------------------------------------------------------
//Ensure a 2nd call for the same ID does not make an HTTP call
sub1.unsubscribe();
const sub2 = service.getThing$('148e265b-b284-84b7-b8b3-441854f15783').subscribe((value: IThing) => {
expect(value).toEqual({
id: '148e265b-b284-84b7-b8b3-441854f15783', otherData: 'foo'
} as IThing);
}, () => {
fail('The subscription to getThing$() has errored out!');
});
httpMock.expectNone('http://our-api/thing/148e265b-b284-84b7-b8b3-441854f15783');
//----------------------------------------------------------------------
//Ensure a 3rd call for a DIFFERENT ID still makes an HTTP request for the new un-cached data
sub2.unsubscribe();
service.getThing$('111e2222-bbbb-8888-cccc-444455555777').subscribe((value: IThing) => {
expect(value).toEqual({
id: '111e2222-bbbb-8888-cccc-444455555777', otherData: 'bar'
} as IThing);
}, () => {
fail('The subscription to getThing$() has errored out!');
});
const req3 = httpMock.expectOne('http://our-api/thing/111e2222-bbbb-8888-cccc-444455555777');
expect(req3.request.method).toEqual('GET');
req3.flush({
id: '111e2222-bbbb-8888-cccc-444455555777', otherData: 'bar'
} as IThing);
});