Reputation: 125
In my Angular application, I am trying to write a unit test case in which I have mocked the rest service response as Observable. So, I have used fakeAsync & tick in my test case. But still it is failing.
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();
}));
});
Now, How can I pass the second test case to check that _onSuccess() has been called from subscribe ?
Upvotes: 0
Views: 3017
Reputation: 18869
I would use HttpClientTesingModule
, it will make testing much easier.
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();
});
});
Check out the above, hopefully it should get you started.
A question I have for you, is the post method takes a body but it doesn't take a URL? I think it should take a url as well.
Edit:
You may have to add .and.callThrough()
to call the actual implementation of what you're spying on.
Like so:
const subscrieSpy = spyOn(Observable.prototype, "subscribe").and.callThrough();
Edit2:
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(...);
Upvotes: 2