如何在 Angular 9 中正确使用 HttpClientTestingModule 和 Jasmine/Karma

How to correctly use HttpClientTestingModule in Angular 9 with Jasmine/Karma

提问人:bilpor 提问时间:5/13/2020 最后编辑:jonrsharpebilpor 更新时间:5/13/2020 访问量:6110

问:

我们有一个通用服务来拨打和接听对后端控制器的调用。在 Angular 4 中,所有测试都可以工作,但由于新的库和更改,它们不再工作。我现在正在尝试使用 和 重写这些。HttpClientTestingModuleHttpTestingController

因此,我们的具体类具有许多函数,目前我专注于我们的方法:getRequest

constructor(
    private configService: ConfigService,
    private userService: UserService,
    private httpClient: HttpClient,
    private errorMapperService: ErrorMapperService) {
  }

  public getRequest(uri: string): Observable<any> {

    const fullUri = this.buildServiceUri(uri);
    const requestHeaders = this.getDefaultRequestHeadersObservable();

    return forkJoin(fullUri, requestHeaders)
      .pipe(flatMap((results: [string, HttpHeaders]) => this.httpClient.get(results[0], { withCredentials: true, headers: results[1] })),
        catchError(this.errorMapperService.handleError));

  }

目前在我的规范文件中,我有:

fdescribe('Api Service', () => {

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientModule,
        HttpClientTestingModule
      ],
      providers: [
        { provide: ApiService },
        { provide: ConfigService },
        { provide: ErrorMapperService },
        { provide: UserService }
      ]
    });
  });

  describe('getRequest', () => {

    const uiServiceUri: string = 'uiServiceUri';
    const expectedResponse: any = { data: '1234', myDate: new Date(2017, 0, 1, 0, 0, 0) };
    const user = new User();
    user.userSession = '<SESSIONTOKEN>';

    let configService: ConfigService;
    let userService: UserService;
    let apiService: ApiService;
    let errorMapperService: ErrorMapperService;

    let httpTestingController: HttpTestingController;

    beforeEach(() => {
      configService = TestBed.get(ConfigService);
      userService = TestBed.get(UserService);
      apiService = TestBed.get(ApiService);
      errorMapperService = TestBed.get(ErrorMapperService);

      httpTestingController = TestBed.get(HttpTestingController);

    });

    describe('with response object',
      () => {

        it('Gets expected response and converts dates to date objects', async(() => {
          apiService.getRequest('test')
            .subscribe((responseObject) => {
              expect(responseObject).toEqual(expectedResponse);
            });

          httpTestingController.expectOne('test').flush(expectedResponse);

          httpTestingController.verify();
        }));
     });
    });

问题是,如果我最初遗漏了针对 httpTestingController 的最后 2 行代码,那么我的期望永远不会达到,并且测试工具说“未找到期望”。如果我重新引入这 2 行,那么我会收到一个失败,指出:

失败:预期一个匹配条件“匹配 URL:测试”的匹配请求, 没有找到。收到的请求包括:GET http://localhost:9876/api/User/、GET http://localhost:9876/api/Config/UiServiceUri、GET http://localhost:9876/api/User/

因此,我将 URL 更改为主 URL,使测试控制器行变为:

httpTestingController.expectOne('http://localhost:9876/api/User/');

然后我收到一个类似的错误,指出只有一个预期,但发现了 2 个。我猜这是因为我的具体类的构造函数。我应该如何编写此测试?

Angular 打字稿 Jasmine

评论

0赞 jonrsharpe 5/13/2020
expect(responseObject).toEqual(expectedResponse);永远不会被到达,因为你没有刷新响应。目前尚不清楚您为什么期望向 or 发出请求,因为在这种情况下的输出显示两个请求,为什么您随后尝试 。请举一个最小的可重复的例子。另请注意,在 angular.io/guide/http#testing-http-requests 中使用 HttpClientTestingModule 进行测试。test.../UserexpectOne
0赞 bilpor 5/13/2020
@jonrsharpe 是的,对不起,在线路之后,我有一个同花顺,但由于条件的原因,它没有被达到。我只是把它放在上面,因为我不知道还能放什么来尝试让它达到我预期的状态。testcontroller 上只有大约 4 个方法,而且它们似乎都不是我真正需要的。expectOneexpectOne
0赞 jonrsharpe 5/13/2020
同样,请提供一个最小的可重复示例。我们看不到各种服务和方法,因此无法在本地复制。
1赞 bilpor 5/13/2020
对我来说,有太多的代码无法创建一个最小的可重复示例。但我认为我的主要问题是我应该从 httpTestingController 对象中使用什么来获得我的期望行。只有 、 和 。从@jonrsharpe评论中的链接来看,在我看来,在我的 beforeEach 中,他们使用了我使用过的地方,但更改为仍然没有区别。expectOneexpectNonematchverifyinjectgetinject
1赞 jonrsharpe 5/13/2020
那么,似乎也可以公平地说,期望我们为您寻找问题时,代码太多了。创建最小示例是调试的第一步。例如,这个 MRE 对我来说效果很好。

答: 暂无答案