Angular 角度HTTP服务-测试失败
我正在学习Angular,并编写了一个服务,该服务仅使用Angular获取一些数据。我在编写验证服务成功获取数据的单元测试时遇到了很多困难。我已经发布了该服务的源代码和测试规范 示例.service.tsAngular 角度HTTP服务-测试失败,angular,angular-httpclient,angular-test,Angular,Angular Httpclient,Angular Test,我正在学习Angular,并编写了一个服务,该服务仅使用Angular获取一些数据。我在编写验证服务成功获取数据的单元测试时遇到了很多困难。我已经发布了该服务的源代码和测试规范 示例.service.ts import { Injectable } from '@angular/core'; import {HttpClient} from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class Ex
import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ExampleService {
constructor(private http: HttpClient) { }
// get some sample data from an remote server
getData() {
return this.http.get('https://jsonplaceholder.typicode.com/todos/1');
}
}
import { TestBed } from '@angular/core/testing';
import { ExampleService } from './example.service';
import {HttpClientTestingModule} from '@angular/common/http/testing';
describe('ExampleService', () => {
let service: ExampleService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule]
});
service = TestBed.inject(ExampleService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
// this is the test that fails
it('getData should return the correct value',
(done: DoneFn) => {
service.getData().subscribe(value => {
console.log('test never reaches this line');
// tslint:disable-next-line
expect(value['userId']).toBe(1);
done();
});
});
});
示例.service.spec.ts
import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ExampleService {
constructor(private http: HttpClient) { }
// get some sample data from an remote server
getData() {
return this.http.get('https://jsonplaceholder.typicode.com/todos/1');
}
}
import { TestBed } from '@angular/core/testing';
import { ExampleService } from './example.service';
import {HttpClientTestingModule} from '@angular/common/http/testing';
describe('ExampleService', () => {
let service: ExampleService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule]
});
service = TestBed.inject(ExampleService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
// this is the test that fails
it('getData should return the correct value',
(done: DoneFn) => {
service.getData().subscribe(value => {
console.log('test never reaches this line');
// tslint:disable-next-line
expect(value['userId']).toBe(1);
done();
});
});
});
getData应返回正确的值
测试失败,错误为错误:超时-异步函数未在5000ms内完成
。我注意到测试从未进入subscribe()
方法。真正奇怪的是,当我在测试框架之外运行getData()
时,它成功地将数据拉回来。我花了几个小时试图解决这个问题,并试图找到一个解决方案,但结果是空手而归。当您对http请求进行单元测试时,您无法使用真正的服务并发出真正的http请求。因此,您必须模拟您的服务,创建伪服务和一个类似的getData()方法,该方法返回一个可观察的数据,与实际方法相同。您可以通过创建一个存根类并使用的RxJS来实现这一点,这是一个可观察的,可以由您的测试类使用
下面是一个如何做到这一点的例子
export class ExampleServiceStub {
constructor() { }
// get some sample data from an remote server
getData() {
return of(
[
{
id: 1,
name: 'Data name'
}
]
);
}
}
在of()中,可以放置实际http请求将返回的数据。您必须像在测试类中注入真正的服务一样注入存根服务。服务方法不一定需要使用
测试床进行单元测试。configureTestingModule
因为它们只是常规类。只有当您想在组件中测试它,或者想为您注入依赖项时,才需要它
因此,也可以在每个测试中手动实例化您的服务,并为其提供所需的依赖项。这也是测试管道和指令的默认方法
要单元测试任何具有网络请求的内容,应模拟网络方法(或“单元”之外的任何内容)。在这种情况下,httpClient
方法不在您的服务范围内,不应该对它们进行测试,因此它们会受到嘲笑
1)要模拟方法,请使用jasmine.createSpyObj
:
let httpClient: { get: jasmine.Spy };
let service: ExampleService;
httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
beforeEach(() => {
service = new ExampleService(<any> httpClientSpy);
});
http测试模块仅在您直接测试http服务时使用。如果目标是测试服务,您可以简单地模拟调用。尝试使用以下指南
it('should return "Yay!"', () => {
const expectedResponse = "[{ hero: 'StackOverflow' }]";
// return expectedResponse when anyone calls get
httpClientSpy.get.and.returnValue(responseData(expectedResponse));
service.getData().subscribe(response => {
expect(service.heroes.length).toEqual(1)
}, fail);
});