使用包装 httpClient 方法的依赖项测试服务
Testing a service with a dependancy that wraps the httpClient methods
我正在尝试测试对 BE 返回数据执行 http 调用的服务。我遇到的问题是,通过 DI 提供了另一种服务,它包装了我希望测试的服务上每个方法的 httpClient 调用。
我正在尝试测试的服务
getValueByUuid(uuid: string): Observable<Value> {
return this._apiService.get<Value>(`${this.endpoint}/${uuid}/`);
}
我们创建了另一种服务,它使用 httpClient 包装标准 REST 方法(获取、post、补丁、删除),允许我们仅在一个地方修改这些请求。
HttpClient Wrapper(上面引用的 _apiService)
get<T>(url: string, options?: {}): Observable<T> {
return this.http
.get(`${this.apiEndpoint}/${url}`, {...options})
.pipe(catchError(this.processError.bind(this)));
}
我试图模拟这个请求,以便我可以创建测试,但由于 httpClient 处于模拟依赖中,我不确定如何最好地做到这一点。
当前尝试
let service: ValueService;
let apiServiceSpy: jasmine.SpyObj<ApiService>;
let httpTestingController: HttpTestingController;
beforeEach(() => {
apiServiceSpy = jasmine.createSpyObj('ApiService', ['get', 'post', 'put', 'delete']);
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{ provide: ApiService, useValue: apiServiceSpy },
ValueService
]
});
service = TestBed.inject(ValueService);
httpTestingController = TestBed.inject(HttpTestingController);
});
it('#getValueByUuid should return a value for a given uuid', () => {
let uuid= "1"
service.getValue(uuid).subscribe(
(res) => {
expect(res).toBeTruthy();
expect(res).toBe(TEST_VALUES[uuid])
}
)
const req = httpTestingController.expectOne(req => req.url === `/value/${uuid}`);
expect(req.request.method).toEqual('GET');
req.flush({results: TEST_VALUES[uuid]})
});
错误
我目前从这种方法中收到以下错误 -
Cannot read property 'subscribe' of undefined
我能找到的唯一一篇文章直接在他们正在测试的服务上使用 HttpClient,因此没有这个问题。
我的处理方式是否正确?我是否应该为“get、post、...等”的每个测试模拟某种可观察到的响应,如果是这样,我将如何去做?
任何帮助将不胜感激,提前致谢!
问题是您在模拟 ApiService
但随后提供了 HttpClient
的测试实现,而真正的 ApiService
需要而不是模拟。
我会一直嘲笑 ApiService
并做这样的事情:
let service: ValueService;
let apiServiceSpy: jasmine.SpyObj<ApiService>;
// !! Get rid of this line !!
// let httpTestingController: HttpTestingController;
beforeEach(() => {
apiServiceSpy = jasmine.createSpyObj('ApiService', ['get', 'post', 'put', 'delete']);
TestBed.configureTestingModule({
// !! don't import HttpClientTestingModule
// imports: [HttpClientTestingModule],
providers: [
{ provide: ApiService, useValue: apiServiceSpy },
ValueService
]
});
service = TestBed.inject(ValueService);
// !! get rid of this line
// httpTestingController = TestBed.inject(HttpTestingController);
});
it('#getValueByUuid should return a value for a given uuid', (done: DoneFn) => {
apiServiceSpy.get.and.returnValue(of({ results: TEST_VALUES[uuid] }));
let uuid= "1"
service.getValue(uuid).subscribe(
(res) => {
expect(res).toBeTruthy();
// see your result
console.log({ res });
done();
}
);
});
我正在尝试测试对 BE 返回数据执行 http 调用的服务。我遇到的问题是,通过 DI 提供了另一种服务,它包装了我希望测试的服务上每个方法的 httpClient 调用。
我正在尝试测试的服务
getValueByUuid(uuid: string): Observable<Value> {
return this._apiService.get<Value>(`${this.endpoint}/${uuid}/`);
}
我们创建了另一种服务,它使用 httpClient 包装标准 REST 方法(获取、post、补丁、删除),允许我们仅在一个地方修改这些请求。
HttpClient Wrapper(上面引用的 _apiService)
get<T>(url: string, options?: {}): Observable<T> {
return this.http
.get(`${this.apiEndpoint}/${url}`, {...options})
.pipe(catchError(this.processError.bind(this)));
}
我试图模拟这个请求,以便我可以创建测试,但由于 httpClient 处于模拟依赖中,我不确定如何最好地做到这一点。
当前尝试
let service: ValueService;
let apiServiceSpy: jasmine.SpyObj<ApiService>;
let httpTestingController: HttpTestingController;
beforeEach(() => {
apiServiceSpy = jasmine.createSpyObj('ApiService', ['get', 'post', 'put', 'delete']);
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{ provide: ApiService, useValue: apiServiceSpy },
ValueService
]
});
service = TestBed.inject(ValueService);
httpTestingController = TestBed.inject(HttpTestingController);
});
it('#getValueByUuid should return a value for a given uuid', () => {
let uuid= "1"
service.getValue(uuid).subscribe(
(res) => {
expect(res).toBeTruthy();
expect(res).toBe(TEST_VALUES[uuid])
}
)
const req = httpTestingController.expectOne(req => req.url === `/value/${uuid}`);
expect(req.request.method).toEqual('GET');
req.flush({results: TEST_VALUES[uuid]})
});
错误
我目前从这种方法中收到以下错误 -
Cannot read property 'subscribe' of undefined
我能找到的唯一一篇文章直接在他们正在测试的服务上使用 HttpClient,因此没有这个问题。
我的处理方式是否正确?我是否应该为“get、post、...等”的每个测试模拟某种可观察到的响应,如果是这样,我将如何去做?
任何帮助将不胜感激,提前致谢!
问题是您在模拟 ApiService
但随后提供了 HttpClient
的测试实现,而真正的 ApiService
需要而不是模拟。
我会一直嘲笑 ApiService
并做这样的事情:
let service: ValueService;
let apiServiceSpy: jasmine.SpyObj<ApiService>;
// !! Get rid of this line !!
// let httpTestingController: HttpTestingController;
beforeEach(() => {
apiServiceSpy = jasmine.createSpyObj('ApiService', ['get', 'post', 'put', 'delete']);
TestBed.configureTestingModule({
// !! don't import HttpClientTestingModule
// imports: [HttpClientTestingModule],
providers: [
{ provide: ApiService, useValue: apiServiceSpy },
ValueService
]
});
service = TestBed.inject(ValueService);
// !! get rid of this line
// httpTestingController = TestBed.inject(HttpTestingController);
});
it('#getValueByUuid should return a value for a given uuid', (done: DoneFn) => {
apiServiceSpy.get.and.returnValue(of({ results: TEST_VALUES[uuid] }));
let uuid= "1"
service.getValue(uuid).subscribe(
(res) => {
expect(res).toBeTruthy();
// see your result
console.log({ res });
done();
}
);
});