如何在Angular中测试HttpClient请求

来自菜鸟教程
跳转至:导航、​搜索

介绍

Angular 的 HttpClient 有一个测试模块,HttpClientTestingModule,它可以让你对 HTTP 请求进行单元测试。

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


在本文中,您将学习如何使用 HttpClientTestingModule 为 HTTP GET 请求设置单元测试。 这将有助于展示测试模块的功能。

先决条件

要完成本教程,您需要:

  • Node.js 安装在本地,您可以按照【X57X】如何安装Node.js 并创建本地开发环境【X126X】进行。
  • 熟悉 设置 Angular 项目

本教程已使用 Node v16.2.0、npm v7.15.1 和 @angular/core v12.0.4 进行了验证。

第 1 步 — 设置项目

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

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

ng new angular-httpclienttest-example

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

cd angular-httpclienttest-example

创建一个 data.service.ts

ng generate service data

并让它与 JSON 占位符通信:

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;
      }
    });
  }
}

并将 HttpClientmodule 添加到 app.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,这使得模拟请求变得容易:

data.service.spec.ts

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 实用程序将所需的服务注入到我们的测试中。

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

data.service.spec.ts

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。
  • 如果 HttpEventTypeResponse 类型,我们断言响应事件的主体等于我们的模拟用户。
  • 然后,我们使用 HttpTestingController(在测试中作为 httpMock 注入)来断言对服务的 url 属性发出了一个请求。 如果没有请求,也可以使用 expectNone 方法。
  • 我们现在可以对模拟请求进行任意数量的断言。 这里我们断言请求没有被取消并且响应的类型是json。 此外,我们可以断言请求的方法 (GET, POST, ...)
  • 接下来,我们在模拟请求上调用 flush 并传入我们的模拟用户。 flush 方法使用传递给它的数据完成请求。
  • 最后,我们在 HttpTestingController 实例上调用 verify 方法,以确保没有未完成的请求。

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

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

ng test

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

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

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

结论

在本文中,您学习了如何使用 HttpClientTestingModule 为 HTTP GET 请求设置单元测试。

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