具有多个HTTP请求的函数的单元测试

时间:2018-06-19 09:56:10

标签: angular typescript karma-jasmine angular-httpclient

我在为间接调用多个HTTP请求的函数编写单元测试时遇到问题。

正在测试的

服务具有以下结构:

/* content.service.ts */
import { Injectable } from "@angular/core"
import { ApiService } from "services/api/api.service"

@Injectable()
export class ContentService {
  public languages: Array<any>
  public categories: Array<any>

  constructor(private apiService: ApiService) {}

  public async fetchLanguages(): Promise<boolean> {
    const data: any = await this.apiService.getData("language")

    if (!data) return false

    this.languages = data
    return true
  }

  public async fetchCategories(): Promise<boolean> {
    const data: any = await this.apiService.getData("category")

    if (!data) return false

    this.categories = data
    return true
  }

  public async initService(): Promise<boolean> {
    const statusLanguages: boolean = await this.fetchLanguages()

    if (!statusLanguages) return false

    const statusCategories: boolean = await this.fetchCategories()

    if (!statusCategories) return false

    return true
  }
}

服务测试文件如下所示:

/* content.service.spec.ts */
import {
  HttpClientTestingModule,
  HttpTestingController
} from "@angular/common/http/testing"
import { TestBed } from "@angular/core/testing"

import { ApiService } from "services/api/api.service"
import { ContentService } from "./content.service"

describe("ContentService:", () => {
  let contentService: ContentService
  let httpMock: HttpTestingController

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ HttpClientTestingModule ],
      providers: [ ApiService, ContentService ]
    })

    contentService = TestBed.get(ContentService)
    httpMock = TestBed.get(HttpTestingController)
  })

  afterEach(() => {
    httpMock.verify()
  })

  /* Dummy data */
  const languages = [
    { id: 1, uid: "en", active: true },
    { id: 2, uid: "es", active: false },
    { id: 3, uid: "hr", active: false }
  ]

  const categories = [
    { id: 1, uid: "default" },
    { id: 2, uid: "alternative" }
  ]

  describe("initService:", () => {
    it("successful response", (done: DoneFn) => {
      contentService.initService().then(result => {
        expect(result).toEqual(true)
        expect(contentService.languages).toEqual(languages)
        expect(contentService.categories).toEqual(categories)
        done()
      })

      const requests = httpMock.match(req => !!req.url.match(/api\/data/))

      expect(requests.length).toBe(2)

      requests[0].flush({ status: "ok", data: languages })
      requests[1].flush({ status: "ok", data: categories })
    })
  })
})

当使用ng test运行单元测试时,会抛出以下错误:

TypeError: Cannot read property 'flush' of undefined

TypeError与该行相关:

requests[1].flush({ status: "ok", data: categories })

这使我得出结论,第一个请求被正确处理,而第二个请求没有。

HttpTestingController中的方法match是否应该捕获与提供的正则表达式匹配的所有HTTP请求?

1 个答案:

答案 0 :(得分:0)

编写单元测试时,您应该只测试一个单元。在这种情况下,您的单位为ContentService。请记住,您不必测试它的依赖项。我看到ApiService是您服务中的依赖,用于发出 Http请求。所以你没有测试你是否正在发出http请求。您只需使用模拟值茉莉花间谍对象来模拟ApiService。

  const spy = jasmine.createSpyObj('ApiService', ['getData']);

  TestBed.configureTestingModule({
    providers: [
      ContentService,
      { provide: ApiService, useValue: spy }
    ]
  });

您需要在此测试的是ContentService内的变量根据输入值获取正确的值和方法的返回值。

您可以单独测试ApiService。在进行单元测试时,不要尝试测试类的依赖关系。