Angular 使用参数 return 模拟的可观察对象测试服务

Angular testing Service with params return an mocked observable

我对所有不同类型的单元测试还是陌生的,而且我又一次被困在服务测试中。

这是我要测试的服务中的功能:

For your information:
this.setParams returns an object like {name: 'Test', id: 3}


  getDataCount(dataparams: Filter): Observable<number> {
    const url = 'http://blablabla.com';
    const params = this.setParams(dataparams);
    return new Observable<number>(observer => {
      this.httpc.get<number>(url, { params }).subscribe(
        (data) => {
          observer.next(data);
          observer.complete();
        }
      );
    }
    );
  }

我的测试设置是:

describe('MyDataService', () => {
  let service: DataService;
  let mockParams: Filter;
  let mockCount: number;

  mockParams = { name: 'Test', id: 3 };
  mockCount = 358;

  beforeEach(() => {

    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule
        ]
    });
    service = TestBed.inject(DataService);
  });

我的测试是这样的:

  it('should return mockCount', async () => {
    const test = await service.getOperatingDataCount(mockParams).toPromise();
    expect(test).toBe(mockCount);
  });

但它正在返回 'Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)'。我也阅读了其他线程,但我仍然无法弄清楚如何为此编写适当的测试。谁能指出我正确的方向?

您应该 await 调用 req.flush() 后的承诺。它将用模拟数据响应,导致 this.httpc.get() Observable 解析。

只有当您的可观察对象发出一个值时,您的承诺才能被解决或拒绝。 因此,在你调用req.flush()之前,promise无法被resolve和rejected,导致超时错误。

这是一个使用 "@angular/core": "~11.0.3"

的工作示例

data.service.ts:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

export type Filter = any;

@Injectable()
export class DataService {
  constructor(private httpc: HttpClient) {}
  setParams(dataparams: Filter) {
    return dataparams;
  }
  getDataCount(dataparams: Filter): Observable<number> {
    const url = 'http://blablabla.com';
    const params = this.setParams(dataparams);
    return new Observable<number>((observer) => {
      this.httpc
        .get<number>(url, { params })
        .subscribe((data) => {
          console.log(data);
          observer.next(data);
          observer.complete();
        });
    });
  }
}

data.service.spec.ts:

import { TestBed } from '@angular/core/testing';
import { DataService, Filter } from './data.service';
import {
  HttpClientTestingModule,
  HttpTestingController,
} from '@angular/common/http/testing';

fdescribe('MyDataService', () => {
  let dataService: DataService;
  let mockParams: Filter;
  let mockCount: number;
  let httpTestingController: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [DataService],
    });
    dataService = TestBed.inject(DataService);
    httpTestingController = TestBed.inject(HttpTestingController);
  });

  it('should get data', async () => {
    mockParams = { name: 'Test', id: 3 };
    mockCount = 358;

    const promise = dataService.getDataCount(mockParams).toPromise();
    const req = httpTestingController.expectOne(
      'http://blablabla.com?name=Test&id=3'
    );
    expect(req.request.method).toEqual('GET');
    req.flush(mockCount);
    const actual = await promise;
    expect(actual).toBe(358);
    httpTestingController.verify();
  });
});

单元测试结果: