Angular 使用 fakeAsync 和 tick 进行单元测试,不等待使用 Observable 执行代码
Angular unit test with fakeAsync and tick not waiting for code to execute with Observable
在我的 Angular 应用程序中,我正在尝试编写一个单元测试用例,其中我将其余服务响应模拟为 Observable。因此,我在测试用例中使用了 fakeAsync & tick。但是还是失败了。
service.ts
import { HttpClient } from "@angular/common/http";
@Injectable()
export class RestServices{
constructor(private _http: HttpClient){}
public post(body: any): void{
// have variables initializations
this._http
.post(url, body, { observe: "response" })
.subscribe(
response => this._onSuccess(response),
error => this._onFailure(error);
);
}
private _onSuccess(response: any){
if(response.status == 200){
// extract data from response
}
}
private _onFailure(error: any){
// code for failure
}
}
service.spec.ts
import { TestBed, tick } from "@angular/core/testing";
import { of } from "rxjs/internal/observable/of";
import { Observable } from "rxjs/internal/Observable";
describe("Rest", () => {
let _service: RestServices;
beforeEach(() => {
const httpSpyObject = jasmine.createSpyObj("HttpClient", {
get: of(),
post: of(new HttpResponse({ status: 200, body: "Text"})),
put: of(),
});
TestBed.configureTestingModule({
providers: [
RestServices,
{ provide: HttpClient, useValue: httpSpyObject }
],
});
_service = TestBed.inject(RestServices);
});
it("should create", () => {
expect(_service).toBeTruthy();
});
it("should call Success method on success response", fakeAsync(() => {
const completeSpy = spyOn<any>(_service, "_onSuccess");
const errorSpy = spyOn<any>(_service, "_onFailure");
const subscrieSpy = spyOn(Observable.prototype, "subscribe");
const body = { name: "abc" };
_service.post(body);
tick(1000);
// Passing the below test case.
expect(subscrieSpy).toHaveBeenCalled();
// not passing below test case
expect(completeSpy).toHaveBeenCalled();
}));
});
现在,我如何通过第二个测试用例来检查 _onSuccess() 是否已从订阅调用?
我会使用 HttpClientTesingModule
,它会使测试更容易。
describe('Rest', () => {
let service: RestService;
let httpTestingController: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [RestService],
});
service = Testbed.inject(RestService);
httpTestingController = TestBed.inject(HttpTestingController);
});
afterEach(() => {
// ensure all http calls are dealt with (none in queue)
httpTestingController.verify();
});
it('creates', () => {
expect(service).toBeTruthy();
});
it('should call success method on success response', () => {
const successSpy = spyOn(service, 'onSuccess');
// 2nd argument is the body
service.post('urlGoesHere', {});
const request = httpTestingController.expectOne('urlGoesHere');
expect(request.request.method).toBe('Post');
// send this for the response
req.flush({});
expect(successSpy).toHaveBeenCalled();
});
});
查看以上内容,希望它能帮助您入门。
我有一个问题要问你,post 方法需要一个主体但不需要 URL?我认为它也应该 url。
编辑:
您可能需要添加 .and.callThrough()
来调用您正在监视的内容的实际实现。
像这样:
const subscrieSpy = spyOn(Observable.prototype, "subscribe").and.callThrough();
编辑2:
let responseBody: any;
// at the beginning
// assign responseBody to response when onSuccess is called
spyOn(service, 'onSuccess').and.callFake(response => responseBody = response);
// after req.flush({});
expect(responseBody).toEqual(...);
在我的 Angular 应用程序中,我正在尝试编写一个单元测试用例,其中我将其余服务响应模拟为 Observable。因此,我在测试用例中使用了 fakeAsync & tick。但是还是失败了。
service.ts
import { HttpClient } from "@angular/common/http";
@Injectable()
export class RestServices{
constructor(private _http: HttpClient){}
public post(body: any): void{
// have variables initializations
this._http
.post(url, body, { observe: "response" })
.subscribe(
response => this._onSuccess(response),
error => this._onFailure(error);
);
}
private _onSuccess(response: any){
if(response.status == 200){
// extract data from response
}
}
private _onFailure(error: any){
// code for failure
}
}
service.spec.ts
import { TestBed, tick } from "@angular/core/testing";
import { of } from "rxjs/internal/observable/of";
import { Observable } from "rxjs/internal/Observable";
describe("Rest", () => {
let _service: RestServices;
beforeEach(() => {
const httpSpyObject = jasmine.createSpyObj("HttpClient", {
get: of(),
post: of(new HttpResponse({ status: 200, body: "Text"})),
put: of(),
});
TestBed.configureTestingModule({
providers: [
RestServices,
{ provide: HttpClient, useValue: httpSpyObject }
],
});
_service = TestBed.inject(RestServices);
});
it("should create", () => {
expect(_service).toBeTruthy();
});
it("should call Success method on success response", fakeAsync(() => {
const completeSpy = spyOn<any>(_service, "_onSuccess");
const errorSpy = spyOn<any>(_service, "_onFailure");
const subscrieSpy = spyOn(Observable.prototype, "subscribe");
const body = { name: "abc" };
_service.post(body);
tick(1000);
// Passing the below test case.
expect(subscrieSpy).toHaveBeenCalled();
// not passing below test case
expect(completeSpy).toHaveBeenCalled();
}));
});
现在,我如何通过第二个测试用例来检查 _onSuccess() 是否已从订阅调用?
我会使用 HttpClientTesingModule
,它会使测试更容易。
describe('Rest', () => {
let service: RestService;
let httpTestingController: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [RestService],
});
service = Testbed.inject(RestService);
httpTestingController = TestBed.inject(HttpTestingController);
});
afterEach(() => {
// ensure all http calls are dealt with (none in queue)
httpTestingController.verify();
});
it('creates', () => {
expect(service).toBeTruthy();
});
it('should call success method on success response', () => {
const successSpy = spyOn(service, 'onSuccess');
// 2nd argument is the body
service.post('urlGoesHere', {});
const request = httpTestingController.expectOne('urlGoesHere');
expect(request.request.method).toBe('Post');
// send this for the response
req.flush({});
expect(successSpy).toHaveBeenCalled();
});
});
查看以上内容,希望它能帮助您入门。
我有一个问题要问你,post 方法需要一个主体但不需要 URL?我认为它也应该 url。
编辑:
您可能需要添加 .and.callThrough()
来调用您正在监视的内容的实际实现。
像这样:
const subscrieSpy = spyOn(Observable.prototype, "subscribe").and.callThrough();
编辑2:
let responseBody: any;
// at the beginning
// assign responseBody to response when onSuccess is called
spyOn(service, 'onSuccess').and.callFake(response => responseBody = response);
// after req.flush({});
expect(responseBody).toEqual(...);