对具有多个 HTTP 请求的函数进行单元测试
Unit test for a function with more than one HTTP request
我在为间接调用多个 HTTP 请求的函数编写单元测试时遇到问题。
正在测试的Service结构如下:
/* 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 请求吗?
编写单元测试时,您应该只测试一个 unit。在这种情况下,您的单位是 ContentService
。请记住,您不必测试它的依赖项。正如我所见,ApiService
是您服务中的一个依赖项,用于发出 Http 请求。所以你没有测试你是否正在发出 http 请求。您只需使用 模拟值 或 jasmine 间谍对象 .
模拟 ApiService
const spy = jasmine.createSpyObj('ApiService', ['getData']);
TestBed.configureTestingModule({
providers: [
ContentService,
{ provide: ApiService, useValue: spy }
]
});
你必须在这里测试的是 ContentService
中的变量根据输入值获得正确的值和方法的 return 值。
您可以单独测试您的 ApiService
。在进行单元测试时,不要尝试测试 类 的依赖关系。
我在为间接调用多个 HTTP 请求的函数编写单元测试时遇到问题。
正在测试的Service结构如下:
/* 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 请求吗?
编写单元测试时,您应该只测试一个 unit。在这种情况下,您的单位是 ContentService
。请记住,您不必测试它的依赖项。正如我所见,ApiService
是您服务中的一个依赖项,用于发出 Http 请求。所以你没有测试你是否正在发出 http 请求。您只需使用 模拟值 或 jasmine 间谍对象 .
const spy = jasmine.createSpyObj('ApiService', ['getData']);
TestBed.configureTestingModule({
providers: [
ContentService,
{ provide: ApiService, useValue: spy }
]
});
你必须在这里测试的是 ContentService
中的变量根据输入值获得正确的值和方法的 return 值。
您可以单独测试您的 ApiService
。在进行单元测试时,不要尝试测试 类 的依赖关系。