Create Project
Create new angular project
ng new testing-samples
Navigate to the project
cd testing-samples
Open VS code
code .
Simple Service
Create a simple service
ng g s post
Service code
@Injectable({
providedIn: 'root'
})
export class PostService {
constructor(private httpClient: HttpClient) { }
getPosts() {
return this.httpClient.get("https://jsonplaceholder.typicode.com/posts")
}
}
App component using service
export class AppComponent implements OnInit {
posts: any = [];
constructor(private postService: PostService) {}
ngOnInit() {
this.postService.getPosts().subscribe((data: any) => {
this.posts = data;
})
}
Unit testing the component
Create spy object for service
postService = jasmine.createSpyObj("PostService", ["getPosts"]);
Tell angular to use it instead of original service
{provide: PostService, useValue: postService}
Setup Code
beforeEach(async () => {
postService = jasmine.createSpyObj("PostService", ["getPosts"]);
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
providers: [
{provide: PostService, useValue: postService}
]
}).compileComponents();
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
});
Set the response when service method is called
postService.getPosts.and.returnValue(of(posts));
Unit test code
it('should set posts oninit - default synchronous way', () => {
var posts = [{
userId: 1,
id: 1,
title: "test",
body: "test"
}
];
postService.getPosts.and.returnValue(of(posts));
fixture.detectChanges(); //triggers onInit
expect(postService.getPosts).withContext("service called").toHaveBeenCalled();
expect(component.posts).withContext("set posts").toBe(posts);
});
Unit testing asynchronous way
Using fakeAsync and tick
Use asyncData helper function to delay the response
function asyncData<T>(data: T) {
return defer(() => Promise.resolve(data));
}
Calling tick()
simulates the passage of time until all pending asynchronous activities finish.
it('should set posts oninit - asynchronous way using fakeasync and tick', fakeAsync(() => {
var posts = [{
userId: 1,
id: 1,
title: "test",
body: "test"
}
];
postService.getPosts.and.returnValue(asyncData(posts));
fixture.detectChanges();
tick();
expect(component.posts).toBe(posts);
}));
Using waitForAsync and whenStable
it('should set posts oninit - asynchronous way using waitForAsync and whenStable', waitForAsync(() => {
var posts = [{
userId: 1,
id: 1,
title: "test",
body: "test"
}
];
postService.getPosts.and.returnValue(asyncData(posts));
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.posts).toBe(posts);
});
}));
Using done function
it('should set posts oninit - using done', (done: DoneFn) => {
var posts = [{
userId: 1,
id: 1,
title: "test",
body: "test"
}
];
let spy = postService.getPosts.and.returnValue(asyncData(posts));
fixture.detectChanges();
spy.calls.mostRecent().returnValue.subscribe(() => {
expect(component.posts).toBe(posts);
done();
});
});
Complete Code
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let postService: any;
function asyncData<T>(data: T) {
return defer(() => Promise.resolve(data));
}
beforeEach(async () => {
postService = jasmine.createSpyObj("PostService", ["getPosts"]);
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
providers: [
{provide: PostService, useValue: postService}
]
}).compileComponents();
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
});
it('should create the app', () => {
expect(component).toBeTruthy();
});
it('should set posts oninit - default synchronous way', () => {
var posts = [{
userId: 1,
id: 1,
title: "test",
body: "test"
}
];
postService.getPosts.and.returnValue(of(posts));
fixture.detectChanges();
expect(postService.getPosts).withContext("service called").toHaveBeenCalled();
expect(component.posts).withContext("set posts").toBe(posts);
});
it('should set posts oninit - asynchronous way using fakeasync and tick', fakeAsync(() => {
var posts = [{
userId: 1,
id: 1,
title: "test",
body: "test"
}
];
postService.getPosts.and.returnValue(asyncData(posts));
fixture.detectChanges();
tick();
expect(component.posts).toBe(posts);
}));
it('should set posts oninit - asynchronous way using waitForAsync and whenStable', waitForAsync(() => {
var posts = [{
userId: 1,
id: 1,
title: "test",
body: "test"
}
];
postService.getPosts.and.returnValue(asyncData(posts));
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.posts).toBe(posts);
});
}));
it('should set posts oninit - using done', (done: DoneFn) => {
var posts = [{
userId: 1,
id: 1,
title: "test",
body: "test"
}
];
let spy = postService.getPosts.and.returnValue(asyncData(posts));
fixture.detectChanges();
spy.calls.mostRecent().returnValue.subscribe(() => {
expect(component.posts).toBe(posts);
done();
});
});
});