使用包装 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();
            }
        );
    });