【问题标题】:Testing a service with a dependancy that wraps the httpClient methods使用包装 httpClient 方法的依赖项测试服务
【发布时间】:2021-07-07 13:17:05
【问题描述】:

我正在尝试测试一个对 BE 返回数据执行 http 调用的服务。我遇到的问题是通过 DI 提供的另一个服务为我希望测试的服务上的每个方法包装了 httpClient 调用。

我正在尝试测试的服务

getValueByUuid(uuid: string): Observable<Value> {
        return this._apiService.get<Value>(`${this.endpoint}/${uuid}/`);
    }

我们创建了另一个服务,它使用 httpClient 封装了标准 REST 方法(get、post、patch、delete),允许我们在一个地方修改这些请求。

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、...等”的每个测试模拟某种可观察到的响应,如果是这样,我将如何去做?

任何帮助将不胜感激,在此先感谢!

【问题讨论】:

  • 你可能需要模拟整个HttpClientModule,你试过this吗?

标签: angular unit-testing jasmine


【解决方案1】:

问题是您在模拟 ApiService,但随后提供了真正的 ApiService 所需的 HttpClient 的测试实现,而不是模拟。

我会一直嘲笑 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();
            }
        );
    });

【讨论】:

  • 谢谢,这是有道理的,然后我可以使用 HttpTestingController 单独对 API 服务进行单元测试。我试图在一个地方做太多事情!
猜你喜欢
  • 1970-01-01
  • 2013-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-16
  • 2017-09-17
  • 1970-01-01
  • 2021-02-01
相关资源
最近更新 更多