如何在 Angular 中测试 HttpClient 请求

介绍

AngularHttpClient有一个测试模块,HttpClientTestingModule可以让您对 HTTP 请求进行单元测试。

注意:由于HttpClient仅从 Angular 4.3 开始可用,因此以下内容适用于 Angular 4.3+。如果您不熟悉 Angular 中的单元测试,请参阅此介绍

在本文中,您将学习如何使用HttpClientTestingModule. 这将有助于展示测试模块的功能。

先决条件

要完成本教程,您需要:

本教程已通过 Node v16.2.0、npmv7.15.1 和@angular/corev12.0.4 验证。

步骤 1 — 设置项目

对于这篇文章,我们将使用从端点获取数据的服务和调用该服务以填充组件OnInit挂钩中的用户列表的组件

您可以使用@angular/cli来创建一个新项目:

  • ng new angular-httpclienttest-example

然后,导航到新创建的项目目录:

  • cd angular-httpclienttest-example

创建一个data.service.ts

  • ng generate service data

并让它与 JSON Placeholder 通信:

src/app/data.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpRequest } from '@angular/common/http';

@Injectable({ ... })
export class DataService {
  url = 'https://jsonplaceholder.typicode.com/users';

  constructor(private http: HttpClient) { }

  getData() {
    const req = new HttpRequest('GET', this.url, {
      reportProgress: true
    });

    return this.http.request(req);
  }
}

然后,修改app.component.ts文件:

src/app.component.ts
import { Component, OnInit } from '@angular/core';
import { HttpEvent, HttpEventType } from '@angular/common/http';

import { DataService } from './data.service';

@Component({ ... })
export class AppComponent implements OnInit {
  users: any;

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.populateUsers();
  }

  private populateUsers() {
    this.dataService.getData().subscribe((event: HttpEvent<any>) => {
      switch (event.type) {
        case HttpEventType.Sent:
          console.log('Request sent!');
          break;
        case HttpEventType.ResponseHeader:
          console.log('Response header received!');
          break;
        case HttpEventType.DownloadProgress:
          const kbLoaded = Math.round(event.loaded / 1024);
          console.log(`Download in progress! ${kbLoaded}Kb loaded`);
          break;
        case HttpEventType.Response:
          console.log('Done!', event.body);
          this.users = event.body;
      }
    });
  }
}

并添加HttpClientmoduleapp.module.ts

src/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

此时,您将拥有一个带有服务和客户端的 Angular 项目。

第 2 步 – 添加测试

现在我们将为我们的数据服务设置一个规范文件,并包含必要的实用程序来测试HttpClient请求。在 之上HttpClientTestingModule,我们还需要HttpTestingController,这使得模拟请求变得容易:

数据服务规范
import { TestBed, inject } from '@angular/core/testing';
import { HttpEvent, HttpEventType } from '@angular/common/http';
import {
  HttpClientTestingModule,
  HttpTestingController
} from '@angular/common/http/testing';

import { DataService } from './data.service';

describe('DataService', () => {
  let service: DataService;

  beforeEach(() => {
    TestBed.configureTestingModule({}
      imports: [HttpclientTestingModule],
      providers: [DataService]
    );
    service = TestBed.inject(DataService);
  });
});

我们使用该inject实用程序将所需的服务注入到我们的测试中。

有了这个,我们可以添加我们的测试逻辑:

数据服务规范
import { TestBed, inject } from '@angular/core/testing';
import { HttpEvent, HttpEventType } from '@angular/common/http';
import {
  HttpClientTestingModule,
  HttpTestingController
} from '@angular/common/http/testing';

import { DataService } from './data.service';

describe('DataService', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [DataService]
    });
  });
  it(
    'should get users',
    inject(
      [HttpTestingController, DataService],
      (httpMock: HttpTestingController, dataService: DataService) => {
        const mockUsers = [
          { name: 'Alice', website: 'example.com' },
          { name: 'Bob', website: 'example.org' }
        ];

        dataService.getData().subscribe((event: HttpEvent<any>) => {
          switch (event.type) {
            case HttpEventType.Response:
              expect(event.body).toEqual(mockUsers);
          }
        });

        const mockReq = httpMock.expectOne(dataService.url);

        expect(mockReq.cancelled).toBeFalsy();
        expect(mockReq.request.responseType).toEqual('json');
        mockReq.flush(mockUsers);

        httpMock.verify();
      }
    )
  );
});

发生了很多事情,所以让我们分解一下:

  • 首先,我们定义了几个我们将测试的模拟用户。
  • 然后我们调用getData我们正在测试的服务中方法并订阅返回的 observable。
  • 如果HttpEventType是 type Response,我们断言响应事件的主体等于我们的模拟用户。
  • 然后,我们使用HttpTestingController(在测试中作为 注入httpMock)来断言对服务的url属性发出了一个请求如果不需要请求,expectNone也可以使用方法。
  • 我们现在可以对模拟请求进行任意数量的断言。这里我们断言请求没有被取消并且响应类型是json此外,我们可以断言请求的方法 ( GET, POST, …)
  • 接下来我们调用flush模拟请求并传入我们的模拟用户。flush方法使用传递给它的数据完成请求。
  • 最后,我们verify在我们的HttpTestingController实例调用该方法以确保没有未完成的请求要发出。

出于本教程的目的,您可以注释掉app.component.spec.ts.

通过运行以下命令查看测试结果:

  • ng test

在浏览器中打开测试结果:

Output
1 spec, 0 failures, randomized with seed 26321 DataService should get users

它将显示成功的测试消息。

结论

在本文中,您学习了如何使用HttpClientTestingModule.

如果您想了解有关 Angular 的更多信息,请查看我们的 Angular 主题页面以获取练习和编程项目。

觉得文章有用?

点个广告表达一下你的爱意吧 !😁